views:

153

answers:

5

Suppose i have:

class A
{
    A(A& foo){ ..... }
    A& operator=(const A& p) {  }
}

...
A lol;
...

A wow(...)
{

    return lol;
}

...
...
A stick;
stick = wow(...);

Then I'll get a compile error in the last line. But if I add 'const' before 'A&', its ok.

I want to know why. Where it's exactly the problem? I dont get why it should be const.

Language: C++

I edited... I think that change its relevant. That gives error.

A: 
KennyTM
I guess GCC has other standars.
fsdfa
@fsdfa: Which compiler (and version) are you using?
KennyTM
3.4.5 MINGW. With and without pedantic I have the error.I dont know teh correspondences between mingw versions and others. Intresiting... maybe its only the compile that force it as a good practice of coding.I have exactly that error
fsdfa
In the provided code, the default assignment operator is being used rather than the provided copy constructor. Which is appropriate, because you aren't constructing an object, you are assigning to it. The default assignment operator operates on const references, so everything is okay. The earlier compilers were probably being overly aggressive with their optimization.
Dennis Zickefoose
@fsdfa: Why not upgrade the MinGW? The latest version is 4.5.0.1.
KennyTM
+1  A: 

The following code compiles perfectly fine with both Comeau and VC9:

class A
{
public:
    A() {}
    A(A&){}
};

A lol;

A wow()
{
    return lol;
}

int main()
{
    A stick;
    stick = wow();
    return 0;
}

If this doesn't compile with your compiler, then I suspect your compiler to be broken. If it does, then that means you should have pasted the real code, instead of supplying a snippet that doesn't resemble the problem you see.

sbi
Why not?, It makes sense, but i dont think thats necessary.
fsdfa
The copyconstructor its called in teh return of the function, the assigment its another thing (in fact, i override it with const)
fsdfa
`wow` copies `lol` into its return value. Then the return value is assigned to `stick` via your assignment operator. The assignment operator accepts const references, so it doesn't mind that you are providing it with an r-value.
Dennis Zickefoose
@Dennis: Wouldn't the compiler generate a cctor? Or wouldn't it because the non-`const` one serves?
sbi
Dennis Zickefoose
+1  A: 

The call to wow results in a temporary object, an r-value. R-values can not be assigned to non-const references. Since your copy constructor accepts non-const references, you can not pass the result of the call to wow directly to it. This is why adding the const fixes the problem. Now the copy constructor accepts const references, which r-values bind to just fine.

Chances are, your copy constructor does not change the object it is copying, so the paramter should be passed by const-reference. This is how copy constructors are expected to work, except in specific, documented circumstances.

But as sbi points out in his answer, this copy constructor shouldn't be getting called at all. So while this is all true, it likely has nothing to do with your problem. Unless there is a compiler bug. Perhaps your compiler sees the two-step construction, and decided it'll cut out the middle man by converting A stick; stick = wow(); into A stick = wow(); But this would be a bug, as evidenced by the fact that it produces a compile error out of perfectly legal code. But without actual code, its impossible to say what's really happening. There should be several other errors before any issues with your copy constructor come up.

Dennis Zickefoose
That's what I thought, too, at first. But given `A stick; stick = wow(...);`, why is that copy ctor called at the _caller's_ side of the `wow()` call?
sbi
Yeah, I just noticed that myself, and was about to edit my answer.
Dennis Zickefoose
@Dennis: ...and the you got stuck, as I did. `:)`
sbi
+1  A: 

I believe the problem you are mentioning is similar to:

http://stackoverflow.com/questions/2462737/c-object-life-time-of-anonymous-unnamed-variables/2463173#2463173

where the essential point is that in C++ anonymous-temporaries can not be passed by reference but only by const reference.

Akanksh
A: 

This function:

A wow(...) 
{  ... }

returns an object of by value.
This means it is copied back to the point where the function was called.

This line:

stick = wow(...);  

Does a copy construction on stick.
The value copied into stick is the value copied back from the function wow().
But remember that the result of the call to wow() is a temporary object (it was copied back from wow() but is not in a variable yet).

So now we look at the copy constructor for A:

A(A& foo){ ..... }

You are trying to pass a temporary object to a reference parameter. This is not allowed. A temporary object can only be bound to a const reference. There are two solutions to the problem:

1) Use a const reference.
2) Pass by value into the copy constructor.

Unfortunately if you use solution (2) you get a bit stuck as it becomes a circular dependency. Passing by value involves using the copy constructor so you enter an infinte loop. So your solution is to use pass by const reference.

Martin York
@Martin: `stick = wow(...);` does __assignment__ on `stick`, not copy-construction. (I ran into that trap, too.)
sbi
The code in the question either isn't the code fsdfa is working with or it's a broken compiler. See my answer: http://stackoverflow.com/questions/2707534/2707542#2707542
sbi