c – 为什么添加析构函数会更改此结构体的复制构造函数行为? [重复]

这个问题已经在这里有一个答案:            >            Rule-of-Three becomes Rule-of-Five with C++11?                                    8个答案                                我有一些代码,我觉得很混乱。特别是当我尝试添加一个列表作为一个初始化器列表 – 它可以工作,直到我添加一个析构函数 – 然后它开始尝试找到一个复制构造函数。

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

#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具有移动构造函数时?

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

隐性移动

如果没有定义,那么对于一个类,一个移动构造函数被隐式声明:

>该类没有用户定义的复制构造函数;和
>该类没有用户定义的副本分配或移动分配运算符;和
>该类没有用户定义的析构函数。

隐性复制

如果没有定义,对于一个类,复制构造函数将被隐式删除:

>该类有一个用户定义的move构造函数;要么
>其他与此无关的原因

在你的问题中你有几种情况:

情况1

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

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

在这种情况下,ListItemType的复制构造函数不能被隐式声明为其数据成员之一(MemberType),它包含一个移动构造函数,这样可以防止生成MemberType的隐式复制构造函数。

情况2

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

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

案例3

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

可以生成ListItemType和MemberType的隐式复制构造函数,并将其用于将值复制到列表中。

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

http://stackoverflow.com/questions/37934997/why-does-adding-a-destructor-change-the-copy-constructor-behavior-of-this-struct

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:c – 为什么添加析构函数会更改此结构体的复制构造函数行为? [重复]