5

我想制作一个容器来管理大对象,这些对象在复制构造和复制分配上执行深复制。

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());

在复制构造函数和赋值运算符中,调试器会跳过这些断点。所以看起来默认的移动成员实际上并不执行深拷贝并移动所有子对象。

标准是否保证了这种行为?默认移动成员的行为是否直观并移动所有子对象?

4

1 回答 1

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>c

在第一种情况下,你有一个直接的初始化,意思c是直接从返回的对象构造make_container()

我强调“概念上”这个词的原因是,在实践中,允许编译器执行复制省略,因此第二个版本很可能会优化为第一个版本(尽管仍然必须检查复制构造函数或移动构造函数的可访问性由编译器)。

于 2013-05-13T12:11:09.157 回答