Move ctor of a class with a constant data member or reference element

I have some problems understanding when and if the constructor move or move assign operator is called, particularly in the context of a class with a constant data member. Consider the class

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 }; 

and test program

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

then the results for compilation differ depending on the definitions provided for the move constructor and the move assignment operator in class A<> , but also for the compiler.

1 without any further declaration in class A<> (as indicated above), both g ++ (4.7.0) and icpc (13.0.1) compile the fine (with the -std=c++11 option) and produce the expected output

 ctor: P=0x7fffffffd480 test: P=0x7fffffffd480 

2 if I declare

 A&A::operator=(A&&) = delete; A&A::operator=(const A&) = delete; 

(which seems reasonable because of the constant data member that should be initialized with an initialized list), but they don't provide any further ctor, compilation fails with g ++, but in the order where icpc is. If, in addition, I define either (or both)

 A::A(A&&) = default; A::A(const A&) = default; 

both compilers are happy. However g ++ is unhappy with the combination

 A::A(A&&) = delete; A::A(const A&) = default; 

while icpc is happy.

3 If I play the same game as in 2 , except that A::A(A&&) = default; replaced by

 A::A(A&&a) : P(aP) { std::cerr<<" move ctor: P="<<P<<'\n'; } // never called? 

(and the equivalent for A::A(const A&) ), the results are completely identical, in particular, there is no way out of these explicit move and copy commands.

So which operator is used for = in main() ? (and why is there no result produced in the last test?)

And why is this operation allowed here at all, given that A<> has a constant data element (the results are identical if I replace the const*T const P; member const*T const P; with const T&R )?

Finally, in the case of different g ++ and icpc behaviors, which, if any, are correct?

+4
source share
1 answer
 A<B> a = b.get_a(); 

not an assignment, but an initialization of a from an r-value. This syntax should fail with C ++ 0x if

  • the move constructor is removed
  • the move constructor is declared explicit ,
  • the copy constructor is deleted and the move constructor is not defined,
  • no move constructor was specified and at the same time, a transfer destination was set or deleted.

Declaring or deleting a copy assignment operator should not have any effect.

Correction: unlike the copy constructor (which is synthesized even if the user-defined copy assignment operator is specified), the compiler does not synthesize the move constructor if the user-defined move destination is defined. Therefore, the above list should be amended 4 (what I did now).

Therefore, in my opinion,

  • in [1] in the question, both compilers behave correctly,
  • in [2] / 1, gcc behaves correctly (assignment movement prevents the creation of a move constructor), icpc is invalid,
  • in [2] / 2, both compilers are correct,
  • in [2] / 3, gcc is correct, since the move constructor is explicitly deleted; icpc is wrong
  • [3] a mystery to me. Are you sure you are right?
+2
source

All Articles