Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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)

like image 710
paercebal Avatar asked Oct 29 '13 15:10

paercebal


People also ask

Why use const in copy constructor?

According to C++ copy constructor, we pass an object by reference to the copy function Object() { [native code] }, and we usually pass it as a const reference. One justification for passing a const reference is that it can use const wherever possible in C++ to avoid unintentionally changing objects.

Why must the parameter of the copy constructor be of type constant reference?

When we create our own copy constructor, we pass an object by reference and we generally pass it as a const reference. One reason for passing const reference is, we should use const in C++ wherever possible so that objects are not accidentally modified.


2 Answers

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.

like image 142
CB Bailey Avatar answered Sep 24 '22 00:09

CB Bailey


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.

like image 44
James Kanze Avatar answered Sep 23 '22 00:09

James Kanze