Reputation: 198
I was reading through this book C++ standard library book
And here is the part i can not understand:
Note that class auto_ptr<> does not allow you to initialize an object with an ordinary pointer by using the assignment syntax.
std::auto_ptr<ClassA> ptr1(new ClassA); //ok
std::auto_ptr<ClassA> ptr2 = new ClassA; //error
I don't understand why it is not allowed. What kind of pitfalls they were trying to avoid by not allowing initialization with assignment syntax
Upvotes: 3
Views: 1698
Reputation: 173004
- I don't understand why it is not allowed.
At first direct initialization and copy initialization are not the same thing.
std::auto_ptr<ClassA> ptr1(new ClassA); //ok
This is direct initialization.
std::auto_ptr<ClassA> ptr2 = new ClassA; //error
This is copy initialization.
Copy-initialization is less permissive than direct-initialization: explicit constructors are not converting constructors and are not considered for copy-initialization.
So if you want to initialize std::auto_ptr
with raw pointer via copy initialization, converting constructor will be needed, but std::auto_ptr
doesn't have it.
std::auto_ptr
's constructor taking one raw pointer as parameter is explicit
, implicit conversion is prohibited.
- What kind of pitfalls they were trying to avoid by not allowing initialization with assignment syntax
Consider about the following code if implicit conversion is allowed:
void f1(ClassA* p) { ... }
void f2(std::auto_ptr<ClassA> p) { ... }
...
ClassA* p = new ClassA;
f2(p); // call the wrong function, ownership is transfered to auto_ptr implicitly
p->something(); // UB, p has been deleted
delete p; // UB
Upvotes: 2
Reputation: 103741
The fact that the assignment syntax cannot be used to initialize an auto_ptr
from a raw pointer is a side effect of the constructor which takes a raw pointer being marked explicit. And the usual reason to mark a constructor as explicit is to prevent things like this:
void take_ownership(std::auto_ptr<ClassA> ptr) {
// the pointer is deleted when this function ends
}
void foo() {
ClassA obj;
take_ownership(&obj); // oops, delete will be called on a pointer to
// an object which was not allocated with new
}
The call to the take_ownership
function is an error there, because of the explicit classifier on the std::auto_ptr
constructor. Instead, you have to deliberately construct an auto_ptr
and pass that to the function.
void foo() {
std::auto_ptr<ClassA> ptr(new ClassA);
take_ownership(ptr); // okay
}
Of course this is not completely impervious to abuse (you can still pass a non-newed object to the constructor of auto_ptr
), it is at least easier to spot when an abuse is taking place.
By the way, std::auto_ptr
is deprecated. It is a very broken class (due to limitations in the language at the time it was introduced). Use std::unique_ptr
instead.
Upvotes: 6
Reputation: 6871
Here is how std::auto_ptr
defined:
template< class T > class auto_ptr;
template<> class auto_ptr<void>;
Hence auto_ptr
is a class type. Let's see its constructors:
explicit auto_ptr( X* p = 0 );
auto_ptr( auto_ptr& r );
template< class Y >
auto_ptr( auto_ptr<Y>& r );
template< class Y >
auto_ptr( auto_ptr_ref<Y> m );
Consider the first constructor. we can use a pointer to X
type object as parameter to call this constructor:
std::auto_ptr<X> ptr1(new X); //ok
In the meanwhile, this first constructor is explicit
, hence we cannot use a pointer to X
type object implicitly to transform to auto_ptr<X>
. In other words, we cannot initialize directly it via a pointer to X
type object.
std::auto_ptr<X> ptr1 = new X; //error; cannot implicitly transform
Upvotes: 2