8
#include <iostream> using namespace std; struct A { A() { cout << "A()" << endl; } ~A() { cout << "~A()" << endl; } A(A&&) { cout << "A(A&&)" << endl; } A& operator =(A&&) { cout << "A& operator =(A&&)" << endl; return *this; } }; struct B { // According to the C++11, the move ctor/assignment operator // should be implicitly declared and defined. The move ctor // /assignment operator should implicitly call class A's move // ctor/assignment operator to move member a. A a; }; B f() { B b; // The compiler knows b is a temporary object, so implicitly // defined move ctor/assignment operator of class B should be // called here. Which will cause A's move ctor is called. return b; } int main() { f(); return 0; } 

My expected output should be:

A() A(A&&) ~A() ~A() 

However, the actual output is: (The C++ compiler is: Visual Studio 2012)

A() ~A() ~A() 

Is this a bug of VC++? or just my misunderstanding?

6
  • 1
    Why do you expect A's move assignment operator to be called? Commented Sep 28, 2012 at 21:19
  • @Prætorian: When RVO is not applied, C++11 says that return b should do a move of b into the return value. Maybe Visual Studio 2012 just doesn't implement C++11 correctly? Commented Sep 28, 2012 at 21:23
  • 2
    @KevinBallard Yes, b should be moved. But that should result in a call to A's move constructor, not the move assignment operator. Commented Sep 28, 2012 at 21:25
  • @Prætorian: Ah, you have a good point. Commented Sep 28, 2012 at 21:25
  • 3
    Beware C++11 is a recent standard. Not all compilers will get everything right just now. Commented Sep 28, 2012 at 21:31

3 Answers 3

14

According to this blog post, VC++ 2012 currently implements N2844 + DR1138, but not N3053. As a result, the compiler is not implicitly generating move constructors or assignment operators for you. If you add explicit default and move constructors to B then you will get the output you expect.

Sign up to request clarification or add additional context in comments.

3 Comments

very sad to hear that. I think this is an extremely fundamental feature of C++11.
Pity, this makes it impractical to 'upgrade' to move semantics, adding move constructors to each movable class, and then to the contained classes, etc. is just too hard.
@Zero : Agreed completely. As a silver lining, if one does nothing right now they're no worse off than before, but when the compiler is eventually improved they'll get those improvements for free just like everyone else did some time earlier. ;-]
7

Visual C++ 2012 does not implement the final C++11 specification for rvalue references and move operations (the specification changed several times during the standardization process). You can find out more information in the Visual C++ Team Blog post, "C++11 Features in Visual C++ 11", under rvalue references.

In your example specifically, this manifests itself in two ways:

  • the definition of the user-defined move operations in A do not suppress the implicitly-declared copy operations.

  • there are no implicitly defined move operations for B.

Comments

1

I don't think generation of the copy ctor is prevented by the declaration of the move constructor. ... and it seems the compiler prefers the copy constructor over the move constructor.

Actually, according to 12.8 [class.copy] paragraph 7 the presence of a move constructor should prevent the copy constructor:

If the class definition does not explicitly declare a copy constructor, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted (8.4).

However, the details of move construction were changed until late in the process and it seems VC++ doesn't implement the actual standard but an earlier revision.

2 Comments

The implicitly declared copy constructor should be declared as deleted if the class has a user-declared move constructor or move assignment operator (it is not deleted here because Visual C++ does not fully implement the final specification).
@JamesMcNellis Yes, I think I remembered an earlier version of the standard and after locating the details I updated the answer accordingly.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.