The "most important const" vs. auto_ptr: Why the code does not compile?
Asked Answered
I

2

6

The following code does not compile on Visual C++ 2008 nor 2010:

#include <memory>

struct A {};

      std::auto_ptr<A> foo()  { return std::auto_ptr<A>(new A); }
const std::auto_ptr<A> bar()  { return std::auto_ptr<A>(new A); }

int main()
{
   const std::auto_ptr<A> & a = foo(); // most important const

   const std::auto_ptr<A> & b = bar(); // error C2558:
                                       // class 'std::auto_ptr<_Ty>' :
                                       // no copy constructor available or copy
                                       // constructor is declared 'explicit'

                                bar(); // No error?
}

I expected the "most important const" to apply to the variable "b", and yet, it does not compile, and for some reason, the compiler asks for a copy constructor (which surprises me as there should be no copy involved here). The standalone call to bar() works fine, which means, I guess, it is really the initialization of b that is the problem.

Is this a compiler bug, or a genuine compilation error described in the standard?

(perhaps it was forbidden in C++98 and authorized in C++11?)

Note: It does compile on Visual C++ 2012, gcc 4.6, and on Solaris CC (of all compilers...), but not gcc 3.4, nor XL C)

Irony answered 29/10, 2013 at 15:20 Comment(14)
did you include <memory>?Billfish
Yeah, I did... :-) ... I'll update the post to show that.Irony
You shouldn't return auto_ptr. it is not a smart pointer. there is no reference count in it. The first destructor of auto_ptr will delete your allocation. and I think you return a reference to bad location.Remise
@Remise it is perfectly fine to return an auto_ptr, if your intention is to transfer ownership to the caller.Louisalouisburg
VC has too many perks that do not obey the standard...Andaman
Returning an auto_ptr is fine because there's a whole lot of auto_ptr_ref trickery specifically designed to make this sort of thing work.Mercurialize
@SHR: The point is to transfer the ownership. And this is Ok (BTW: If you're using exclusively shared_ptr, then you probably have something wrong in your code). Note that I'm still wondering at the real-like use of a function returning a const std::auto_ptr, but this is beside the point.Irony
@CharlesBailey While returning an std::auto_ptr is fine, the bigger question is why he's using a deprecated template to begin with. stdL::unique_ptr should be used here.Johannisberger
@Zac Howland : the bigger question is why he's using a deprecated template to begin with. stdL::unique_ptr should be used here : Because some compilers are still not C++11-enabled, perhaps?... :-)Irony
@ZacHowland: Possibly because if you are using VS2008, VS2010, gcc 3.4 and xlC, there is no unique_ptr in std. auto_ptr is at least standardized in the version of C++ supported by all those compilers.Mercurialize
@CharlesBailey He has C++11 tagged, which would seem to indicate he can utilize the newer C++ features.Johannisberger
-Wbind-to-temporary-copyScuba
@Zac Howland : He has C++11 tagged, which would seem to indicate he can utilize the newer C++ features : Not really: 1. Your observation is wrong because I added both the C++98 and C++11 tags because (and thus after) your initial comment... :-) ... 2. Your deduction is wrong because when you are cross-compiling (which I obviously am), you must use the common subset among the different compilers, not the features specific to two compilers among seven... Good try, anyway... :-)Irony
@paercebal: I didn't keep up with the timeline of events, but if you added it after my initial comment, there is no need for the C++11 tag as you are only really asking what can be supported pre-C++11 (which you hint at with your #2). Thus, it isn't a matter of "cross compiling", but actually compiling using an older standard. C++11 is not, in an of itself, a compiler - it is a standard to which the compilers are written. If you are attempting to write portable code, you write your code to the standard, not to features a compiler may or may not support.Johannisberger
M
13

In C++03 and C++98, when binding a const reference to an rvalue (such as a function returning by value), the implementation may bind the reference directly to the rvalue or it may make a copy of the rvalue and bind the reference to that copy. As auto_ptr's copy constructor takes a non-const reference, this second choice will only work if the rvalue returned is not const qualified but the compiler is still allowed to attempt this, even if it won't work.

In C++11, these extra copies are not allowed and the implementation must bind directly to the rvalue if a conversion isn't required.

See also here.

Mercurialize answered 29/10, 2013 at 15:36 Comment(0)
S
1

Pre C++11, at least, the standard required an object to be copyable in this context. In the end, the semantics of:

T const& t = f();

, where f returns a T by value, is:

T tmp = f();
T const& t = tmp;

Which requires a copy constructor.

In the case of std::auto_ptr, the problem that you're seeing is that the copy constructor is defined to take a non-const reference, which means that you cannot copy a temporary. Some compilers (e.g. Microsoft) don't enforce this, which means that your code may work with them, but it is fundamentally illegal.

The real question is why you are using references here. You need a local variable one way or the other; the reference only introduces an additional layer of indirection.

Saidel answered 29/10, 2013 at 16:0 Comment(1)
No, this is not the real question: This is not my code. I was only curious about why this code would not compile... +1 BTW...Irony

© 2022 - 2024 — McMap. All rights reserved.