实施例
struct MyObject {
MyObject(int value):value(value) { }
MyObject(MyObject const&o):value(o.value) { }
int value;
};
假设复制构造函数除了有用之外还执行某些操作。然后
std::function<void()> f() {
MyObject o;
std::vector<int> v;
return [=]() { /* use v and o */ &o; &v; }
}
首先将 v
和o
复制到初始lambda对象中,这很好。但每次需要移动lambda对象时,它们都会被再次复制。即使v
可以移动,但事实并非如此。那是因为lambda没有隐式移动构造函数,因为o
没有移动构造函数或普通的复制构造函数。
有人可以解释一下这背后的理由吗?
答案 0 :(得分:6)
我似乎记得这是两个极端之间的妥协,那些根本不想隐式生成移动构造函数的人,以及那些希望移动构造函数在大多数情况下自动生成的人。
在不想隐式生成移动构造函数的人中,Dave Abrahams写了一篇名为 Implicit Move Must Go 的文章。理由是,在某些情况下,即使成员可移动,隐式生成移动构造函数也可以打破不变量。
今年早些时候(2011年),委员会决定将隐式生成移动构造函数保留在一个决策中,这个决策似乎强调了现有代码在安全问题上的性能提升(1),并且Dave {{ 3}}关于它。它没有谈论决定的具体细节,利弊,但对结果也不太满意。
编辑(来自Jerry Coffin):这里是隐式声明移动构造函数的条件列表:
If the definition of a class X does not explicitly declare a move constructor,
one will be implicitly declared as defaulted if and only if
— X does not have a user-declared copy constructor,
— X does not have a user-declared copy assignment operator,
— X does not have a user-declared move assignment operator,
— X does not have a user-declared destructor, and
— the move constructor would not be implicitly defined as deleted.
基本思想是在课堂中包含任何这些内容都表明隐式生成的移动ctor可能会出现错误行为。虽然这是真的,但是列表中的条件对于确定来说既不必要也不充分,因此很多有用的移动因素都不会产生,并且可能会产生很多会导致问题的因素。更糟糕的是,这些规则已经很长很复杂,很少有人记住它们,修复它们可能至少会加倍 [Jerry的贡献/咆哮结束]
(1)感谢Gene Bushuyev对于决定采取何种决定的看法
答案 1 :(得分:1)