[shared_ptr] constructor accepting auto_ptr

Hi. There's a shared_ptr constructor that accepts an auto_ptr<Y>&. Shouldn't it accept auto_ptr<Y> by value rather by non-const reference? It seems to me that the reference does not add anything, but only causes a VC warning (level 4): --- warning C4239: nonstandard extension used : 'argument' : conversion from 'std::auto_ptr<_Ty>' to 'std::auto_ptr<_Ty> &' A reference that is not to 'const' cannot be bound to a non-lvalue --- when calling this constructor with a temporary auto_ptr. This warning is a good thing and I don't want to disable it. Thanks, Yuval

Yuval Ronen wrote:
Hi. There's a shared_ptr constructor that accepts an auto_ptr<Y>&. Shouldn't it accept auto_ptr<Y> by value rather by non-const reference? It seems to me that the reference does not add anything,
The reference adds a strong exception safety guarantee. If the shared_ptr constructor fails, the source auto_ptr is left intact. Pass by value would have already zeroed out the source. If you want to achieve the equivalent of pass by value, you can use an explicit .release().
but only causes a VC warning (level 4):
--- warning C4239: nonstandard extension used : 'argument' : conversion from 'std::auto_ptr<_Ty>' to 'std::auto_ptr<_Ty> &' A reference that is not to 'const' cannot be bound to a non-lvalue ---
when calling this constructor with a temporary auto_ptr. This warning is a good thing and I don't want to disable it.
This warning would actually be an error on a stricter compiler. One happy day the compiler writers will bring us the rvalue reference, the constructor will take auto_ptr &&, and all will be well with the world. :-)

Peter Dimov wrote:
The reference adds a strong exception safety guarantee. If the shared_ptr constructor fails, the source auto_ptr is left intact. Pass by value would have already zeroed out the source.
If you want to achieve the equivalent of pass by value, you can use an explicit .release().
This warning would actually be an error on a stricter compiler.
One happy day the compiler writers will bring us the rvalue reference, the constructor will take auto_ptr &&, and all will be well with the world. :-)
Does that mean that on a stricter compiler, when passing a temporary auto_ptr, I *have* to use the '.release()' way, and *can't* get the strong exception guarantee? Thanks a lot to both of you Peter and Howard for your help.

Yuval Ronen wrote:
Peter Dimov wrote:
The reference adds a strong exception safety guarantee. If the shared_ptr constructor fails, the source auto_ptr is left intact. Pass by value would have already zeroed out the source.
If you want to achieve the equivalent of pass by value, you can use an explicit .release().
This warning would actually be an error on a stricter compiler.
One happy day the compiler writers will bring us the rvalue reference, the constructor will take auto_ptr &&, and all will be well with the world. :-)
Does that mean that on a stricter compiler, when passing a temporary auto_ptr, I *have* to use the '.release()' way, and *can't* get the strong exception guarantee?
Yes, and no. It means it can't be a temporary if you want the strong exception guarantee. I.e. you would have to assign the temporary to an lvalue first: auto_ptr<X> a = returns_some_auto_ptr_x(); shared_ptr<X> b(a); -- -- Grafik - Don't Assume Anything -- Redshift Software, Inc. - http://redshift-software.com -- rrivera/acm.org - grafik/redshift-software.com -- 102708583/icq - grafikrobot/aim - Grafik/jabber.org

Yuval Ronen wrote:
Peter Dimov wrote:
The reference adds a strong exception safety guarantee. If the shared_ptr constructor fails, the source auto_ptr is left intact. Pass by value would have already zeroed out the source.
If you want to achieve the equivalent of pass by value, you can use an explicit .release().
This warning would actually be an error on a stricter compiler.
One happy day the compiler writers will bring us the rvalue reference, the constructor will take auto_ptr &&, and all will be well with the world. :-)
Does that mean that on a stricter compiler, when passing a temporary auto_ptr, I *have* to use the '.release()' way, and *can't* get the strong exception guarantee?
Yes it does, but when your source is a temporary, it doesn't make any difference; even if it's left unchanged by the constructor, it will be destroyed at the end of the full expression, along with the pointee.

Peter Dimov wrote:
Yuval Ronen wrote:
Does that mean that on a stricter compiler, when passing a temporary auto_ptr, I *have* to use the '.release()' way, and *can't* get the strong exception guarantee?
Yes it does, but when your source is a temporary, it doesn't make any difference; even if it's left unchanged by the constructor, it will be destroyed at the end of the full expression, along with the pointee.
Ok, I see. Thanks.

On Dec 7, 2005, at 10:01 AM, Yuval Ronen wrote:
Hi. There's a shared_ptr constructor that accepts an auto_ptr<Y>&. Shouldn't it accept auto_ptr<Y> by value rather by non-const reference? It seems to me that the reference does not add anything, but only causes a VC warning (level 4):
--- warning C4239: nonstandard extension used : 'argument' : conversion from 'std::auto_ptr<_Ty>' to 'std::auto_ptr<_Ty> &' A reference that is not to 'const' cannot be bound to a non-lvalue ---
when calling this constructor with a temporary auto_ptr. This warning is a good thing and I don't want to disable it.
This shared_ptr ctor is designed such that if it throws, the auto_ptr arg retains ownership of the pointer. To transfer ownership from an rvalue auto_ptr you could: shared_ptr<Y> sp(get_auto_ptr().release()); The semantics of this latter statement are different than the ctor your pointed out only under exceptional conditions. Now if the shared_ptr ctor throws, the pointer is deleted instead of being retained by the auto_ptr. By having these two options, shared_ptr allows the client to choose which semantics work best in any given situation. <musing> A future shared_ptr might: shared_ptr(auto_ptr<T>&&); // or move_ptr This would allow lvalues or rvalues to bind, and retain the same semantics as we have today for lvalue auto_ptr's. This is just off the cuff, food for thought... </musing> -Howard

Yuval Ronen wrote:
Hi. There's a shared_ptr constructor that accepts an auto_ptr<Y>&. Shouldn't it accept auto_ptr<Y> by value rather by non-const reference? It seems to me that the reference does not add anything, but only causes a VC warning (level 4):
--- warning C4239: nonstandard extension used : 'argument' : conversion from 'std::auto_ptr<_Ty>' to 'std::auto_ptr<_Ty> &' A reference that is not to 'const' cannot be bound to a non-lvalue ---
when calling this constructor with a temporary auto_ptr. This warning is a good thing and I don't want to disable it.
Thanks, Yuval
Don't call the constructor with a temporary. Anyway, there's a good reason for this: the semantics of auto_ptr. auto_ptr works with transfer of ownership: there can only be one auto_ptr at any time holding a specific pointer. When you assign or copy-construct auto_ptrs, ownership is transferred: the old pointer is set to NULL. Due to this, the auto_ptr will always destruct its pointee when it gets destructed. auto_ptr does not care about shared_ptr's reference count. To have shared_ptr not point to deleted memory, constructing a shared_ptr from an auto_ptr must prevent auto_ptr from deleting the pointee. And the only way to do that is to set it to NULL. This is why it needs to be passed as non-const reference; otherwise you couldn't modify it. Note that auto_ptr's own copy constructor and assignment operator also take non-const references. So even if you made shared_ptr's constructor take an auto_ptr by value, you'd still get the warning, this time from auto_ptr's constructor. Only this time you'd have an additional, useless temporary. Sebastian Redl
participants (5)
-
Howard Hinnant
-
Peter Dimov
-
Rene Rivera
-
Sebastian Redl
-
Yuval Ronen