xmllmx
xmllmx

Reputation: 42235

Why do not C++11's move constructor/assignment operator act as expected

#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?

Upvotes: 8

Views: 3207

Answers (3)

Dietmar K&#252;hl
Dietmar K&#252;hl

Reputation: 153800

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.

Upvotes: 1

James McNellis
James McNellis

Reputation: 355009

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.

Upvotes: 7

ildjarn
ildjarn

Reputation: 62975

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.

Upvotes: 14

Related Questions