我有一些代码让我感到困惑.特别是,当我尝试将某些内容添加到列表作为初始化列表时 - 它一直有效,直到我添加析构函数 - 然后它开始尝试查找复制构造函数.
这似乎并不是完全一致的行为.拿这个最小的例子:
#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;
}
Run Code Online (Sandbox Code Playgroud)
这无法在GCC和VS2015中编译,因为push_back尝试访问ListItemType复制构造函数:
main()::ListItemType::ListItemType(const main()::ListItemType&)
Run Code Online (Sandbox Code Playgroud)
(根据我的理解).这似乎是有道理的,因为列表push_back将复制(因为没有移动构造函数),除非这不是行为,如果您删除析构函数.注释掉析构函数,编译按预期成功.
也就是说,即使使用析构函数,以下工作也很好 - 不需要复制或移动构造函数来满足它.这对我来说似乎是一样的行为.
ListItemType foo = { MemberType() };
Run Code Online (Sandbox Code Playgroud)
最后,如果删除或注释掉移动构造函数MemberType- 编译再次成功 - 意味着以下将编译.
#include <list>
int main()
{
class MemberType
{
public:
MemberType() {}
};
struct ListItemType
{
MemberType x;
~ListItemType() {}
};
std::list<ListItemType> myList;
myList.push_back({MemberType()});
return 0;
}
Run Code Online (Sandbox Code Playgroud)
有人可以解释一下这里的行为吗?为什么push_back尝试访问复制构造函数ListItemType- 但只有ListItemType具有析构函数并且MemberType具有移动构造函数?
don*_*mus 27
您正在观察的行为是由管理编译器生成隐式复制或移动构造函数的规则生成的:
如果未定义,则在以下情况下为类隐式声明移动构造函数:
如果未定义,则在以下情况下隐式删除类的复制构造函数:
在您的问题中,您有几种情况:
ListItemType 有一个析构函数MemberType 有一个移动构造函数ListItemType由于存在析构函数,隐式移动构造函数已被删除.因此push_back必须使用复制构造函数将其ListItemType放入列表中.
在这种情况下,复制构造函数ListItemType不能被隐式声明为其数据成员之一(MemberType)包含一个移动构造函数,它可以防止MemberType生成隐式复制构造函数.
ListItemType 没有析构函数MemberType 有一个移动构造函数可以隐式生成移动构造函数,ListItemType并将其用于将值移动到列表中.
ListItemType 有一个析构函数MemberType 没有移动构造函数对于隐式的拷贝构造函数ListItemType和MemberType可以产生和使用的值复制到列表中.
最后,表达式ListItemType foo = { MemberType() };是聚合初始化并遵循不同的规则.在任何一种情况下MemberType都将具有足以进行聚合初始化的移动或复制构造函数.