Question

C++11

I'm having trouble using the move constructor. I have a simple container class, called Number, whose only data member is an integer. I have the following code:

//Number.h
#ifndef NUMBER_H
#define NUMBER_H
#include <iostream>

class Number
{
public:
    Number();
    Number(int ipar);
    Number(const Number& src);
    Number(Number&& src);
private:
    int num;
};

#endif

and

//Number.cpp
#include "Number.h"

Number::Number()
{
    std::cout << "default ctor" << std::endl;
}

Number::Number(int ipar) : num(ipar)
{
    std::cout << "integer argument ctor" << std::endl;
}

Number::Number(const Number& src) : num(src.num)
{
    std::cout << "copy ctor" << std::endl;
}

Number::Number(Number&& src) : num(src.num)
{
    std::cout << "move ctor" << std::endl;
}

and

//main.cpp
#include "Number.h"
using namespace std;

int main()
{
    cout << "Part A:" << endl;
    Number n1(1);
    cout << "Part B:" << endl;
    Number n2(n1);
    cout << "Part C:" << endl;
    Number n3{Number{n1}};
    cout << "Part D:" << endl;
    Number n4(Number(n1));
    return 0;
}

This outputs:

Part A:
integer argument ctor
Part B:
copy ctor
Part C:
copy ctor
Part D:

Notice there is no output for Part D. The output for Parts A and B are what I expected, but the output for the others aren’t.

I expected this for Parts C and D:

Part C:
copy ctor
move ctor
Part D:
copy ctor
move ctor

Expectation for Part C:

I expected the Number{n1} part of Number n3{Number{n1}} to make a temporary nameless Number object, because there is no name between Number and the opening curly brace, by calling the copy constructor with n1. Then I expected Number n3 to be constructed by calling the move constructor with the temporary object.

Expectation for Part D:

Since this is like Part C, except with parentheses instead of curly braces, I expected this part to behave and output in the same way I expected Part C to.

Question:

Why does the actual output differ from my expectations and what is the correct way to get my desired output?

Note: If you want to compile this in Visual Studio, you need the Visual C++ Compiler November 2012 CTP or later for Visual Studio 2012 in order to support the uniform initialization syntax.

Was it helpful?

Solution

n4 is a function declaration. n3 is caused by copy elision.

Check that here I've enabled -fno-elide-constructors to avoid copy elision. n3 then shows a sequence of copy and move constructors.

There's a commented out line that tries to use n4 as an object. If you uncomment it, you'll see the compiler error telling it's a function instead.

For n4 do not be interpreted as a function declaration you could put extra parentheses around the temporary to prevent it from being viewed as a function parameter: Number n4((Number(n1))). With this and -fno-elide-constructors all you've expected happens.

Note that -fno-elide-constructors is not present as an option in MSVC.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top