tags:

views:

784

answers:

2

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 he's wrong).

+7  A: 
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.ahmed
That's not true. All modern compilers will create identical code from both of these examples.
Marcin
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.ahmed
FWIW, I'm less concerned with "create identical code" than the formal equivalence or non-equivalence of the statements.
Kristopher Johnson
Marcin, but it will still check semantics of the call.
Johannes Schaub - litb
even though it optimizes temporaries
Johannes Schaub - litb
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
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
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
+11  A: 
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
Thats what i tried to explain. I guess I failed.
fasih.ahmed
Sorry, I didn't mean to have the "explicit" in the question. I've updated it.
Kristopher Johnson
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
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
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