移动具有常量数据成员或引用成员的类的ctor
move ctor of class with a constant data member or a reference member
我在理解何时以及是否调用移动构造函数或移动赋值运算符时遇到了一些问题,尤其是在具有常量数据成员的类的上下文中。考虑类
template<typename T> class A {
const*T const P ; // constant data member
explicit A(const*T p) : P(p) { std::cerr<<" ctor: P="<<P<<'n'; }
void test() const { std::cerr" test: P="<<P<<'n'; }
// move and copy constructors and assignment operators here
};
和测试程序
class B {
int X[100];
A<B> get_a() const { return A<B>(this); }
};
int main() {
B b;
A<B> a = b.get_a(); // which operator/ctor is used for '=' here?
a.test();
}
则编译的结果取决于为类A<>
中的移动构造函数和移动赋值运算符提供的定义以及编译器。
1在类A<>
中没有任何进一步的声明(如上所述),g++(4.7.0)和icpc(13.0.1)都可以很好地编译(使用选项-std=c++11
)并产生预期的输出
ctor: P=0x7fffffffd480
test: P=0x7fffffffd480
2如果我申报
A&A::operator=(A&&) = delete;
A&A::operator=(const A&) = delete;
(考虑到必须初始化的常量数据成员列表,这似乎是合理的),但不提供任何进一步的ctor,编译失败,使用g++,但可以使用icpc。如果另外我定义中的一个(或两个)
A::A(A&&) = default;
A::A(const A&) = default;
两位编译人员都很高兴。然而,g++对的组合并不满意
A::A(A&&) = delete;
A::A(const A&) = default;
而icpc很高兴。
3如果我玩与2中相同的游戏,除了A::A(A&&) = default;
被取代
A::A(A&&a) : P(a.P) { std::cerr<<" move ctor: P="<<P<<'n'; } // never called?
(相当于A::A(const A&)
),结果完全相同,特别是没有从这些显式移动和复制因子生成输出。
那么main()
中的=
使用了哪个运算符呢?(为什么在上次测试中没有输出?)
既然A<>
有一个恒定的数据成员(如果我用const T&R
替换成员const*T const P;
,结果是相同的),为什么这里允许这种操作?
最后,在g++和icpc的不同行为的情况下,如果有的话,哪一个是正确的?
A<B> a = b.get_a();
不是赋值,而是从右值初始化a
。如果
- 移动构造函数被删除
- 移动构造函数被声明为CCD_ 12
- 复制构造函数被删除并且没有定义移动构造函数
- 没有定义move构造函数,同时定义或删除了move赋值
声明或删除副本分配运算符不应产生任何影响。
更正:与复制构造函数(即使提供了用户定义的复制赋值运算符也会合成)不同,如果定义了用户定义移动赋值,编译器不会合成移动构造函数。因此,上述清单应修改为4(我现在已经这样做了)。
因此,在我看来,
- 在问题[1]中,两个编译器的行为都是正确的
- 在[2]/1中,gcc行为正确(move赋值阻止生成move构造函数),icpc错误
- 在[2]/2中,两个编译器都是正确的
- 在[2]/3中,gcc是正确的,因为move构造函数被显式删除;icpc错了
- [3] 对我来说是个谜。你确定你是对的吗
相关文章:
- 将成员变量添加到共享库中的类中,不会破坏二进制兼容性吗
- 对RValue对象调用的LValue ref限定成员函数
- 为什么使用 "this" 指针调用派生成员函数?
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- 助记符和指向成员语法的指针
- 用于访问容器<T>数据成员的正确 API
- 内置函数可查看CPP中的成员变量
- 是否可以初始化不可复制类型的成员变量(或基类)
- C2436 '{ctor}':构造函数初始值设定项列表中的成员函数或嵌套类
- 为什么在 ctor 的参数列表中将成员"x"的类型替换为"decltype(x)"会破坏类模板参数推导?
- 初始化在类类型 #define 中定义的非静态成员数组,不带默认 ctor
- 使用非默认 Ctor 初始化类类成员
- 为什么我不能对具有成员初始值设定项列表的默认 ctor 使用 =default。
- 复制 ctor 与互斥锁作为数据成员
- 如何在G 代码中找到给定的成员函数或CTOR的所有位置
- 移动类的数组成员所需的ctor
- 移动具有常量数据成员或引用成员的类的ctor
- 在 ctor 中使用 const&vector 初始化的 const&vector 成员
- {ctor} 不是 的成员<BaseClass>
- 禁止在没有用户定义 ctor 的情况下显式复制数据成员