views:

1017

answers:

4

Simple question: are the following statements equivalent? or is the second one doing more implicit things behind the scenes (if so, what?)

myClass x(3);
myClass x = myClass(3);

Thanks!

+7  A: 

The second one may or may not call for an extra myclass object construction if copy elision is not implemented by your compiler. However, most constructors, have copy elision turned on by default even without any optimization switch.

Note initialization while construction never ever calls the assignment operator.

Always, keep in mind:

assignment: an already present object gets a new value

initialization: a new object gets a value at the moment it is born.

dirkgently
This has got nothing to do with NRVO whatsoever.
Konrad Rudolph
I meant the elision, couldn't come up with the right term at the time. Thanks.
dirkgently
+5  A: 

In the second one, a temporary object is created first and then is copied into the object x using myClass's copy constructor. Hence both are not the same.

Naveen
+17  A: 

They are not completely identical. The first is called "direct initialization" while the second is called "copy initialization".

Now, the Standard makes up two rules. The first is for direct initialization and for copy initialization where the initializer is of the type of the initialized object. The second rule is for copy initialization in other cases.

So, from that point of view both are termed in one - the first - rule. In the case where you have copy initialization with the same type, the compiler is allowed to elide a copy, so it can construct the temporary you create directly into the initialized objet. So you can end up very well with the same code generated. But the copy constructor, even if the copy is elided (optimized out), must still be available. I.e if you have a private copy constructor, that code is invalid if the code in which it appears has no access to it.

The second is called copy-initialization, because if the type of the initializer is of a different type, a temporary object is created in trying to implicitly convert the right side to the left side:

myclass c = 3;

The compiler creates a temporary object of the type of myclass then when there is a constructor that takes an int. Then it initializes the object with that temporary. Also in this case, the temporary created can be created directly in the initialized object. You can follow these steps by printing messages in constructors / destructors of your class and using the option -fno-elide-constructors for GCC. It does not try to elide copies then.

On a side-note, that code above has nothing to do with an assignment operator. In both cases, what happens is an initialization.

Johannes Schaub - litb
with VC9 "myclass c = 3" seems to just call "myclass(int x)" directly, rather than a using a temporary myclass object.
Fire Lancer
VC is broken in this regard. It has a rule similar to: "Use direct initialization wherever possible".
Richard Corden
+3  A: 

I wrote the following to try and illustrate understand what's going on:

#include <iostream>

using namespace std;

class myClass
{
public:
    myClass(int x)
    {
        this -> x = x;
        cout << "int constructor called with value x = " << x << endl;
    }

    myClass(const myClass& mc)
    {
        cout << "copy constructor called with value = " << mc.x << endl;
        x = mc.x;
    }

    myClass & operator = (const myClass & that)
    {
        cout << "assignment called" << endl;
        if(this != &that)
        {
            x = that.x;
        }
        return *this;
    }

private:
    int x;
};

int main()
{
    myClass x(3);
    myClass y = myClass(3);
}

When I compile and run this code I get the following output:

$ ./a.out
int constructor called with value x = 3
int constructor called with value x = 3

This would seem to indicate that there is no difference between the two calls made in the main function, but that would be wrong. As litb pointed out, the copy constructor must be available for this code to work, even though it gets elided in this case. To prove that, just move the copy constructor in the code above to the private section of the class definition. You should see the following error:

$ g++ myClass.cpp 
myClass.cpp: In function ‘int main()’:
myClass.cpp:27: error: ‘myClass::myClass(const myClass&)’ is private
myClass.cpp:37: error: within this context

Also note that the assignment operator is never called.

Bill the Lizard
But if I remove the copy constructor from that code entirely, it still works. What does that imply?
Baltimark
That implies that your compiler is inserting a default copy constructor for you.
Bill the Lizard
Sure, no problem.
Bill the Lizard