Re: [boost] Re: Re: Re: Querying the Interest in a new AutoPtr class?

Jonathan Turkanis wrote:
I wanted to create a very simple AutoPtr that was essentially the same as the STL auto_ptr (and backwards compatible with it).
Unfortunately, you haven't (see below). Furthermore, auto_ptr is widely recognized as unsafe because it is too easy to transfer ownership unintentionally.
Of course you can unintentionally transfer ownership if you don't know what you're doing. ;)
The problem is that the code which transfers ownership appears innocuous on the surface, because auto_ptr allows transfer of ownership with the same syntax ordinarily used for copying:
void f() { auto_ptr<int> ptr(new int); auto_ptr<int> ptr2(ptr); // ptr is now empty. }
Why would anyone in their right mind do that?
I believe that's why you're not supposed to pass an auto_ptr to a function -- instead you pass the pointer itself with .get(). You can't stop everyone from shooting themselves in the foot.
Declaring a function to take an argument of type auto_ptr<...> is one way to signal that ownership is being transfered to the function. It also ensures that the managed object will be deleted, unless the function takes explicit steps to cause a leak. Passing raw pointers defeats this system.
Yes, this is true if you're calling a function that you wrote and compiled yourself, but if you're calling a 3rd party API that you didn't compile yourself, that can be dangerous (or so I've been told).
How? If you pass a pointer to a function, you shouldn't be deleting it inside that function anyways (so pass it with .get()),
What if you want to transfer ownership to the function, as is often the case?
Then pass ptr.release() to the function.
and if you return a pointer from a function, you can save it in a new AutoPtr so it will get deleted automatically...
This depends on the calling code to do the right thing. If you return an auto_ptr, the managed object will be freed even if the calling code choses to ignore the return value.
I agree, if it's your own code, return an auto_ptr, but if you're an API, you must return a raw pointer.
I don't set my pointer to NULL when I release() it, I just set m_Owner = false.
This behavior is not compatible with std::auto_ptr.
I could change it to set the pointer to NULL, but this is what Microsoft's auto_ptr does, and it looked safer.
move_ptr has the same overhead as auto_ptr.
Thanks, when I get some time I'll take a look at those. As you might infer from some of my comments, I'm dealing mostly with API component code myself, which integrates some older sub components, so I have no choice but to pass raw pointers most of the time. Chris Just __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com

On Mon, 14 Feb 2005 09:41:20 -0800 (PST), Chris Just <cpjust@yahoo.com> wrote:
I don't set my pointer to NULL when I release() it, I just set m_Owner = false.
This behavior is not compatible with std::auto_ptr.
I could change it to set the pointer to NULL, but this is what Microsoft's auto_ptr does, and it looked safer.
Keeping an address that you no longer control around sounds a LOT less safe than setting it to 0 to me. The STL implementation that shipped with VC6 and which you've used as your jumping-off-point is known to be exceedingly buggy. The auto_ptr in VC7.x sets its internally held pointer to 0 in the release method (and no longer has an owner flag). -- Caleb Epstein caleb dot epstein at gmail dot com

Chris Just wrote:
The problem is that the code which transfers ownership appears innocuous on the surface, because auto_ptr allows transfer of ownership with the same syntax ordinarily used for copying:
void f() { auto_ptr<int> ptr(new int); auto_ptr<int> ptr2(ptr); // ptr is now empty. }
Why would anyone in their right mind do that?
By accident, perhaps? The point is, why allow such errors to creep into code when they can be prevented at compile time?
Declaring a function to take an argument of type auto_ptr<...> is one way to signal that ownership is being transfered to the function. It also ensures that the managed object will be deleted, unless the function takes explicit steps to cause a leak. Passing raw pointers defeats this system.
Yes, this is true if you're calling a function that you wrote and compiled yourself, but if you're calling a 3rd party API that you didn't compile yourself, that can be dangerous (or so I've been told).
Dangeous how? Actually the opposite is true: if you declare such a function to take a raw pointer, callers might think they still own the pointer after calling the function, or the function might not clean up the resource properly.
How? If you pass a pointer to a function, you shouldn't be deleting it inside that function anyways (so pass it with .get()),
What if you want to transfer ownership to the function, as is often the case?
Then pass ptr.release() to the function.
See above.
and if you return a pointer from a function, you can save it in a new AutoPtr so it will get deleted automatically...
This depends on the calling code to do the right thing. If you return an auto_ptr, the managed object will be freed even if the calling code choses to ignore the return value.
I agree, if it's your own code, return an auto_ptr, but if you're an API, you must return a raw pointer.
Why?
I don't set my pointer to NULL when I release() it, I just set m_Owner = false.
This behavior is not compatible with std::auto_ptr.
I could change it to set the pointer to NULL, but this is what Microsoft's auto_ptr does, and it looked safer.
The old Dinkumware library that shipped with VC5-6 is not a good model.
move_ptr has the same overhead as auto_ptr.
Thanks, when I get some time I'll take a look at those.
As you might infer from some of my comments, I'm dealing mostly with API component code myself, which integrates some older sub components, so I have no choice but to pass raw pointers most of the time.
Yes, we all have to do this sometimes.
Chris Just
Jonathan

From: Chris Just <cpjust@yahoo.com>
Jonathan Turkanis wrote:
I wanted to create a very simple AutoPtr that was essentially the same as the STL auto_ptr (and backwards compatible with it).
Unfortunately, you haven't (see below). Furthermore, auto_ptr is widely recognized as unsafe because it is too easy to transfer ownership unintentionally.
Of course you can unintentionally transfer ownership if you don't know what you're doing. ;)
The problem is that the code which transfers ownership appears innocuous on the surface, because auto_ptr allows transfer of ownership with the same syntax ordinarily used for copying:
void f() { auto_ptr<int> ptr(new int); auto_ptr<int> ptr2(ptr); // ptr is now empty. }
Why would anyone in their right mind do that?
You wouldn't do that. He was simply illustrating the point with a simple example. The point is, any time you construct one auto_ptr from another, ownership is transferred.
I believe that's why you're not supposed to pass an auto_ptr to a function -- instead you pass the pointer itself with .get(). You can't stop everyone from shooting themselves in the foot.
Declaring a function to take an argument of type auto_ptr<...> is one way to signal that ownership is being transfered to the function. It also ensures that the managed object will be deleted, unless the function takes explicit steps to cause a leak. Passing raw pointers defeats this system.
Yes, this is true if you're calling a function that you wrote and compiled yourself, but if you're calling a 3rd party API that you didn't compile yourself, that can be dangerous (or so I've been told).
It is exactly the thing to do with any function if you intend to transfer ownership of the memmory referenced by the point in or out of a function. The mere fact that a function takes or returns an auto_ptr is documenting and requiring the transfer of ownership. You can't escape the transfer and that's the point. Consider a function returning an auto_ptr. If someone calls the function, ostensibly for some side effect of the call, and the function returns a pointer to allocated memory, what happens if the caller ignores the return value? The compiler doesn't offer any help when you ignore a return value, so it is not hard to write code that does so. If the function returns a raw pointer to newly allocated memory, the memory is leaked because the caller ignored it rather than deleting it. OTOH, if the function returns an auto_ptr to that memory, the memory will be released unless the caller release()es it and then forgets to delete it. IOW, if the caller ignores the return value of such a function, the temporary auto_ptr it returns will go out of scope and delete the memory it was given to manage. The bottom line is that it is perfectly safe and quite desirable to return an auto_ptr from a function. Now consider a function taking an auto_ptr argument. That function is quite clearly documenting that it is taking ownership of the memory; it will delete the memory or transfer ownership to yet another object that will manage the memory. The caller must supply an auto_ptr as the constructor is explicit. Unfortunately if the caller already has an auto_ptr, there's no information at the call site that the transfer will occur. (That's what Jonathan was trying to illustrate with his example above. Looking just at the second line, there's nothing that screams "ptr is losing ownership of its memory as a result of this call.") The bottom line is that it is not as desirable to take an auto_ptr function argument from the caller's perspective, but it is still appropriate if that's all you have at your disposal. Then again, as Jonathan has been pointing out, you can use move_ptr, the upcoming PBSP, or even the reference counted shared_ptr, just to mention a few types in Boost.
How? If you pass a pointer to a function, you shouldn't be deleting it inside that function anyways (so pass it with .get()),
What if you want to transfer ownership to the function, as is often the case?
Then pass ptr.release() to the function.
Then how does the function document that it is deleting the memory and the caller had better not reference the memory after the call? Comments aren't good at this, though taking an auto_ptr argument is only slightly better.
and if you return a pointer from a function, you can save it in a new AutoPtr so it will get deleted automatically...
This depends on the calling code to do the right thing. If you return an auto_ptr, the managed object will be freed even if the calling code choses to ignore the return value.
I agree, if it's your own code, return an auto_ptr, but if you're an API, you must return a raw pointer.
No, if the function returns allocated memory that the caller must delete, then the function should return a smart pointer. In this context, auto_ptr is exactly the right answer. In others, shared_ptr might be what you want.
I don't set my pointer to NULL when I release() it, I just set m_Owner = false.
This behavior is not compatible with std::auto_ptr.
I could change it to set the pointer to NULL, but this is what Microsoft's auto_ptr does, and it looked safer.
It permits clients of your smart pointer to reference dangling pointers. That's not a good plan.
As you might infer from some of my comments, I'm dealing mostly with API component code myself, which integrates some older sub components, so I have no choice but to pass raw pointers most of the time.
The best way to deal with such APIs is to wrap them in a safer version that traffics in smart pointers. That way, only those wrapper functions have to be scrutinized to ensure they are correctly managing memory and all the rest of your code can avoid raw pointers and the dangers they pose. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;
participants (4)
-
Caleb Epstein
-
Chris Just
-
Jonathan Turkanis
-
Rob Stewart