14

Given a class like this:

class Foo {
public:
    Foo(int);

    Foo(const Foo&);

    Foo& operator=(int);

private:
    // ...
};

Are these two lines exactly equivalent, or is there a subtle difference between them?

Foo f(42);

Foo f = 42;

Edit: I confused matters by making the Foo constructor "explicit" in the original question. I've removed that, but appreciate the answers.

I've also added declaration of a copy constructor, to make it clear that copying may not be a trivial operation.

What I really want to know is, according to the C++ standard, will "Foo f = 42" directly call the Foo(int) constructor, or is the copy constructor going to be called?

It looks like fasih.ahmed has the answer I was looking for (unless it's wrong).

Kristopher Johnson
  • 81,409
  • 55
  • 245
  • 302

2 Answers2

21
class Foo {
public:
    Foo(explicit int);

    Foo& operator=(int);
};

That's invalid. The syntax is

class Foo {
public:
    explicit Foo(int);

    Foo& operator=(int);
};

The difference is that the conversion constructor cannot be used for implicit conversions when you put explicit before it:

Foo f(10); // works
Foo f = 10; // doesn't work

The above doesn't have anything to do with an assignment operator you declared there. It is not used since that is an initialization (only constructors are used). The following will use the assignment operator:

Foo f;
f = 10;

And will use the default constructor of Foo (the one taking no arguments).


Edit: The questioner changed his question to the specific ways of whether

Foo f = 1; // called "copy initialization" 
Foo f(1);  // called "direct initialization"

Are the same. The answer is that they are equivalent to the following:

Foo f(Foo(1));
Foo f(1);

If and only if the conversion constructor taking the int is not declared with keyword explicit, otherwise the first is a compiler error (see above). The compiler is allowed to elide (optimize out) the temporary passed to the copy constructor of Foo in the first case if all semantic restrictions are still safisfied, and even if the copy constructor has side effects. That especially includes a visible copy constructor.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • Thats what i tried to explain. I guess I failed. – fasih.rana Dec 16 '08 at 21:14
  • Sorry, I didn't mean to have the "explicit" in the question. I've updated it. – Kristopher Johnson Dec 16 '08 at 21:16
  • still i don't think i will delete that part of my answer. the bottom part answers what your assignment op is for – Johannes Schaub - litb Dec 16 '08 at 21:30
  • Thanks for the detailed explanation. It's rules like "The compiler is allowed to elide... even if the copy ctor has side effects" that make me hate C++ sometimes. I mean, how could they make it any more confusing and potentially damaging??? – j_random_hacker Jan 09 '09 at 07:46
  • j_random_hacker. i think it's because the copy constructor is used to copy instances. if there is no copy necassary, why should it copy? the cctor should not change any global state anyway (it should just initialize *this). i think it's reasonable to allow the compiler to not make the copy then. – Johannes Schaub - litb Jan 09 '09 at 12:00
  • Foo f(10); // works Foo f = Foo(10); // this is the correct way. – benlong Apr 02 '14 at 02:25
9
Foo f = 42;

This statement will make a temporary object for the value '42'.

Foo f(42);

This statement will directly assign the value so one less function call.

fasih.rana
  • 1,645
  • 1
  • 14
  • 27
  • That's not true. All modern compilers will create identical code from both of these examples. – Marcin Dec 16 '08 at 20:59
  • Just today I was playing with this and modern compilers failed to create identical code. I'm talking latest version of gcc on Linux Enterprise Server 5. Try running that code and you'll find out. – fasih.rana Dec 16 '08 at 21:10
  • 1
    FWIW, I'm less concerned with "create identical code" than the formal equivalence or non-equivalence of the statements. – Kristopher Johnson Dec 16 '08 at 21:22
  • Marcin, but it will still check semantics of the call. – Johannes Schaub - litb Dec 16 '08 at 21:36
  • even though it optimizes temporaries – Johannes Schaub - litb Dec 16 '08 at 21:36
  • Foo f = 42 is equivalent to Foo f (Foo(42)) in any conforming compiler. If the copy constructor implementation is not available when compiling the call, it cannot be optimised, since the constructor might have side effects. – Gorpik Dec 16 '08 at 21:42
  • 1
    Ups, sorry for the previous comment. According to the standard, the compiler is allowed to do the optimisation even if the copy constructor implementation is not available. So, if the constructor does indeed have side effects, the call is somewhat undefined. – Gorpik Dec 16 '08 at 21:45
  • Gorphik, it aren't the side effects. even tho there are side effects, the copy can still be elided. the point is the visibility of the copy constructor, and no the compiler is *not* allowed to elide the copy if the copy constructor is not visible. – Johannes Schaub - litb Dec 16 '08 at 21:50