views:

138

answers:

4

Please consider the following code,

struct foo
{
    foo()
    {
        std::cout << "Constructing!" << std::endl;
    }

    foo(const foo& f)
    {
        std::cout << "Copy constructing!" << std::endl;
    }

    ~foo()
    {
        std::cout << "Destructing.." << std::endl;
    }
};

foo get()
{
    foo f;
    return f;
}

int main()
{
    const foo& f = get();
    std::cout << "before return" << std::endl;
    return 0;
}

Output on MSVC

Constructing!
Copy constructing!
Destructing..
before return
Destructing..

Output of GCC

Constructing!
before return
Destructing..

The result which comes on MSVC looks incorrect.

Questions

  1. AFAIK, GCC produces the correct result here. Why MSVC is giving different results and why it is doing copy construction?
  2. const foo& f = get() and const foo f = get() produces same output because of return value optimization. In this case, which way of writing should be preferred?

Any thoughts..

A: 

1) This happens because of different optimization strategy. Because you don't have operator=, MSVC can restructure code to something like const foo& f(get()) therefore executing copy onstructor. 2) Depends on what you want to acheive:

const foo& f = get();
f = get(); // Incorrect, const references cannot be reassigned.
const foo g = get();
g = get(); // Correct.
Glorphindale
I think you completely misunderstand the meaning of the const modifier. "g = get();" is also an error.
Ben Voigt
You're right. My knowledge of C++ is ruined by 2.5 years in testing :(
Glorphindale
+11  A: 

Your MSVC build has no optimizations on. Turn them on, you'll get identical output for both.

GCC is merely performing, by default, RVO on your temporary. It's basically doing:

const foo& f = foo();

MSVC is not. It's making the foo in the function, copying it to the outside the function (ergo the copy-constructor call), destructing the inner foo, then binds the reference.

Both outputs are correct. RVO is one instance where the standard explicitly allows the observable behavior of the program to change.

GMan
Yes. I just discovered it now. I changed the optimization level and it is behaving identically.
Appu
Appu
GMan
Thanks GMan and others for the help...:)
Appu
Also probably worth to point out that in C++0x the former is allowed to copy the return value before binding the const reference. In C++0x this copying is disallowed: As long as the called function has access to the copy constructor (to copy a local variable into the return value), the line should be fine (the calling code no longer needs access to the copy constructor).
Johannes Schaub - litb
+1  A: 

You are seeing the return value optimization, which is one kind of copy elision. Both programs are correct; the compiler is specifically given the option of eliminating a temporary which only serves to move data from one permanent object to another.

Potatoswatter
+1  A: 

The get() function is Constructing the local (print Constructing!), and returning a Foo object by value. The Foo object being returned must be created and is done so via copy construction (print Copy constructing!). Note that this is the object value assigned to the const foo & f in main.

Before that assignment takes place though, the function must return from get() and local variables (i.e. foo f; in get()) must be destroyed. (print 1st Destructing..) From there the program terminates (i.e. returns from main) then the object returned by get() and assigned to "f" is destroyed. (print 2nd Destructing...)

The reason you're seeing different output for the two compilers is that GCC is optimizing the return value for get() and is simply replacing const foo &f = get() to const foo &f = foo;

RC