【发布时间】:2012-11-13 23:22:17
【问题描述】:
我在理解何时以及是否调用移动构造函数或移动赋值运算符时遇到了一些问题,特别是在具有常量数据成员的类的上下文中。 考虑类
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&)),结果完全相同,特别是没有输出从这些显式移动和复制ctors中生成。
那么main()中的=使用的是哪个运算符? (为什么最后一次测试没有输出?)
鉴于A<> 有一个常量数据成员(如果我将成员const*T const P; 替换为const T&R,结果是相同的),为什么这里完全允许此操作?
最后,对于g++和icpc的不同行为,如果有的话,哪个是正确的?
【问题讨论】:
标签: c++ constructor c++11 move-semantics