我想创建一个管理大对象的容器,它可以在复制构造和复制分配上执行深层复制。
template <class TBigObject>
class Container : public std::vector< std::shared_ptr<TBigObject> >
{
public:
Container(int nToAllocate){ /* fill with default constructed TBigObjects */ }
Container(const Container& other){ /* deep copy */ }
Container(Container&&) = default;
Container& operator = (const Container& population){ /* deep copy */ }
Container& operator = (Container&&) = default;
};
我想知道违约是什么:
Container(Container&&) = default;
Container& operator = (Container&&) = default;
成员确实这样做了。
如果我打电话:
Container<int> makeContainer()
{
...
}
并在以下位置设置调试断点:
Container<int> moveAssigned;
moveAssigned = makeContainer(); // EDIT corrected thanks to Andy Prowl
Container<int> moveConstructed(makeContainer());
并且在复制构造函数和赋值运算符内部,调试器跳过这些断点。因此,默认移动成员实际上不执行深层复制并移动所有子对象。
标准是否保证了这种行为?默认的移动成员是否行为直观并移动所有子对象?
答案 0 :(得分:8)
默认的移动成员是否行为直观并移动所有子对象?
是。根据C ++ 11标准的第12.7 / 15段:
非联合类X的隐式定义的复制/移动构造函数执行成员复制/移动 其基地和成员。 [...]
顺便说一下,这个:
Container<int> moveAssigned = makeContainer();
不是移动分配,而是使用复制初始化语法的移动构造。移动任务将是:
Container<int> moveAssigned;
// ...
moveAssigned = makeContainer(); // <== MOVE ASSIGNMENT HERE
这之间的区别:
Container<int> c(make_container());
而且:
Container<int> c = make_container();
是概念上,在第二种情况下,首先从右侧的表达式构造类型为Container<int>
的临时对象,然后{ {1}}是从这个临时构造中移动构建的。
在第一种情况下,您有一个直接初始化,这意味着c
将直接从c
返回的对象构建。
我强调“概念上”这个词的原因是,在实践中,允许编译器执行复制省略,因此第二个版本可能会优化到第一个版本(尽管复制构造函数或移动构造函数的可访问性必须仍然由编译器检查。)