3

Does a C++ compiler automatically convert:

MyObject object2 = object1;

into

MyObject object2( object1 );

?

Or does it treat it like:

MyObject object2;
object2 = object1;

?

mskfisher
  • 3,291
  • 4
  • 35
  • 48
PP.
  • 10,764
  • 7
  • 45
  • 59
  • If it was a real performance problem, you'd probably already know the answer. In general, don't worry about micro-optimizations like this unless it's in a bottleneck and you've found it to cause a real problem. If you want to know whether a compiler does optimization X, assume that the answer is yes. – Chris Lutz Aug 25 '11 at 16:37
  • I guess I was also interested in best practice. Whether or not it is a micro optimisation depends a lot on the size of the object and the size/frequency of the function that creates it. – PP. Aug 26 '11 at 09:47
  • @PP - Yes, the degree that this might be an optimization _does_ depend on those things. Which is why you shouldn't bother optimizing unless you've profiled and found it to be a problem. – Chris Lutz Aug 26 '11 at 17:16

4 Answers4

8

Yes, it's the first one. It's not an "optimisation"; they are two different syntaxes for invoking the copy constructor.

If you want to prove it, try defining a private assignment operator for MyObject. The code should still compile, which proves it can't be equivalent to the second mechanism.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • 2
    Is there some issue about explicit copy constructors, though? – Kerrek SB Aug 25 '11 at 16:36
  • 2
    @Kerrek: yes, the initialization with equals will not consider explicit constructors. – R. Martinho Fernandes Aug 25 '11 at 16:42
  • @Kerrek: Given `type a = b;` where the type of `b` is not `type`, that is transformed into an *implicit* conversion from `b` to `type` and copy constructor of `a` from the temporary (pseudo-coe): `type a( implicit_conversion(b) );`. What Oli has stated is exactly correct: it is another syntax to invoke the *copy constructor* (not *any* constructor), and the implicit/explicit conversions only affect in as much as the argument might have to be converted before calling the copy constructor. – David Rodríguez - dribeas Aug 25 '11 at 18:44
  • 1
    ... also note that there is not only the issue with explicitness of the constructor. Because the type is converted *before* calling the copy constructor, if the copy constructor cannot take an *rvalue* (i.e. if it is declared as: `type::type( type & );` --which is a valid signature), then it will also fail to compile. Again, the reason is that the syntax is in fact an alternative syntax for *copy construction*. – David Rodríguez - dribeas Aug 25 '11 at 18:46
  • @David: So if `a` and `b` are of the same type, can I always say `type a = b;`, even if the copy constructor is explicit? – Kerrek SB Aug 25 '11 at 18:48
2

You can try this to see the exact behavior:

#include <iostream>

class MyObject {
public:
    MyObject() {
        std::cout << "MyObject()" << std::endl;
    }
    MyObject(const MyObject& other) {
        std::cout << "MyObject(const MyObject& other)" << std::endl;
    }
    MyObject& operator=(const MyObject& other) {
        std::cout << "operator=(const MyObject& other)" << std::endl;
        return *this;
    }
};

int main() {
    MyObject object1;
    MyObject object2 = object1;
    MyObject object3(object1);
    MyObject object4;
    object4 = object1;
}

Outputs:

MyObject()
MyObject(const MyObject& other)
MyObject(const MyObject& other)
MyObject()
operator=(const MyObject& other)

Apart from that, I recommend reading What is The Rule of Three?

Community
  • 1
  • 1
jweyrich
  • 31,198
  • 5
  • 66
  • 97
  • Thank you for the clear example code. As you can see some of the answers have conflicted. This leaves no doubt. – PP. Aug 26 '11 at 09:50
2

What gets called with MyObject object2 = object1; is a constructor because this is initialization. This has nothing to do with the assignment operator.

However, the transformation you suggested from MyObject object2 = object1; into MyObject object2(object1); does not happen, because these two initialization syntaxes are not the same. They are similar in that they both initialize an object by calling a constructor, but they have a slight difference.

If you have:

struct MyObject {
    explicit MyObject(MyObject const&);
};

Then MyObject object2 = object1; is ill-formed, but MyObject object2(object1); is well-formed.

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
1
MyObject object2 = object1;

is copy-initialization. This will call the copy constructor, if object1 is of type MyObject.

If object1 is of a different type then it will either do an implicit conversion from object1 to MyObject, and then either copy-construct object2 from that, or do the implicit conversion directly into object2 and skip the copy construction. The copy constructor (or move constructor in C++11) must be accessible in both cases.

Anthony Williams
  • 66,628
  • 14
  • 133
  • 155