c++ - 为什么添加析构函数会更改此结构的复制构造函数行为?

标签 c++ c++11

我有一些令我感到困惑的代码。特别是,当我尝试将某些内容作为初始值设定项列表添加到列表中时——它会一直工作,直到我添加一个析构函数——然后它开始尝试找到一个复制构造函数。

这似乎不是完全一致的行为。举个最小的例子:

#include <list>
int main()
{
    class MemberType
    {
    public:
        MemberType()  {}
        MemberType(MemberType&& copy) { }
    };
    struct ListItemType
    {
        MemberType x;
        ~ListItemType() {}
    };
    std::list<ListItemType> myList;
    myList.push_back({MemberType()});
    return 0;
}

GCC 中编译失败和 VS2015 因为 push_back 尝试访问 ListItemType 复制构造函数:

main()::ListItemType::ListItemType(const main()::ListItemType&)

(根据我的理解)。这似乎是有道理的,因为列表 push_back 将进行复制(因为没有移动构造函数),除非这是 不是 删除析构函数时的行为。注释掉析构函数,编译按预期成功。

也就是说,即使使用析构函数,以下内容也可以正常工作 - 不需要复制或移动构造函数来满足它。不过,这对我来说似乎是相同的行为。

ListItemType foo = { MemberType() };

最后,如果你删除或注释掉 MemberType 的移动构造函数 - 编译再次成功 - 意味着以下将编译。

#include <list>
int main()
{
    class MemberType
    {
    public:
        MemberType()  {}
    };
    struct ListItemType
    {
        MemberType x;
        ~ListItemType() {}
    };
    std::list<ListItemType> myList;
    myList.push_back({MemberType()});
    return 0;
}

有人可以解释一下这里的行为吗?为什么 push_back 尝试访问 ListItemType 的复制构造函数 - 但前提是 ListItemType 具有析构函数和 MemberType有移动构造函数吗?

最佳答案

您观察到的行为是由管理编译器是否生成隐式复制或移动构造函数的规则生成的:

隐式移动

如果未定义,则为类隐式声明移动构造函数,如果:

  • 该类没有用户定义的复制构造函数;和
  • 该类没有用户定义的复制赋值或移动赋值运算符;和
  • 该类没有用户定义的析构函数。

隐式复制

如果未定义,则在以下情况下为类隐式删除复制构造函数:

  • 该类有一个用户定义的移动构造函数;或
  • 其他与此处无关的原因...

在您的问题中,您有几种情况:

案例一

  • ListItemType 有一个析构函数
  • MemberType 有一个移动构造函数

由于析构函数的存在,ListItemType 的隐式移动构造函数已被删除。因此 push_back 必须使用复制构造函数将 ListItemType 放入列表中。

在这种情况下,ListItemType 的复制构造函数不能隐式声明为它的数据成员之一 (MemberType) 包含移动构造函数,这会阻止隐式复制构造函数MemberType 正在生成。

案例2

  • ListItemType 没有析构函数
  • MemberType 有一个移动构造函数

可以为 ListItemType 隐式生成移动构造函数,并用于将值移动到列表中。

案例3

  • ListItemType 有一个析构函数
  • MemberType 没有移动构造函数

ListItemTypeMemberType 的隐式复制构造函数可以生成并用于将值复制到列表中。

最后,表达式 ListItemType foo = { MemberType() }; 是聚合初始化,遵循不同的规则。在任何一种情况下,MemberType 都将具有足以进行聚合初始化的移动或复制构造函数。

关于c++ - 为什么添加析构函数会更改此结构的复制构造函数行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37934997/

相关文章:

c++ - g++ 4.7.1 中奇怪的迭代器行为

c++ - 有没有像 QString(或 Java String)这样的 C++ 字符串库?

c++ - 将标准输出重定向到父进程控制台窗口

c++ - block 评论开头的感叹号有什么用?

C++11:迭代时从 std::unordered_map 中删除单个元素是否安全?

c++ - C++ 在线预处理器

pointers - 将 unique_ptr/shared_ptr 与 API 函数结合使用,通过指针将资源作为输出参数返回

c++ - 如何使用 QOpenGLWidget 渲染文本

c++ - numpy.dot 比原生 C++11 慢 100 倍

c++ - 我什么时候应该按值返回,而不是返回一个唯一的指针