views:

881

answers:

7

std::auto_ptr is broken in VC++ 8 (which is what we use at work). My main gripe with it is that it allows auto_ptr<T> x = new T();, which of course leads to horrible crashes, while being simple to do by mistake.

From an answer to another question here on stackoverflow:

Note that the implementation of std::auto_ptr in Visual Studio 2005 is horribly broken. http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=98871 http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=101842

I want to use

  • boost::scoped_ptr, for pointers that shouldn't pass ownership.
  • boost::shared_ptr, for pointers in containers and elsewhere where they are required.
  • std::auto_ptr, for pointers that should/can pass ownership.

But since std::auto_ptr is broken for me, I wonder what would be the best approach:

  • Replace std::auto_ptr with something from the net. Like this this one from Rani Sharoni (haven't tried it yet).
  • Use boost::shared_ptr instead. Will of course work, although there will be some minor overhead that I don't care about. But I want to use auto_ptr to signal the intent of the pointer. (See this answer for a vote on this approach.)
  • I will never need to pass ownership in practice, so I shouldn't worry about this.


Update: Here is what I did: I copied the aforementioned auto_ptr implementation by Rani Sharoni. From here.

Did some minor tests:

class T
{
public:
    T() {
     OutputDebugStringA("T\n");
    };
    ~T() {
     OutputDebugStringA("~T\n");
    };
};

{
    fix::auto_ptr<T> x(new T); // This just works.
}
{
    fix::auto_ptr<T> x = (new T); // Doesn't compile. Great!
}
{
    fix::auto_ptr<T> x = fix::auto_ptr<T>(new T); // Transfer of ownership works also.
}

Of course these tests are by no means exhaustive and you shouldn't trust them. Implementing an exception safe templated class is hairy business. At least this works better than the built in one.

Note: I don't know if I'm allowed to use this implementation yet, with respect to copyright. I have emailed Rani and I'm waiting for a reply. I'll update this post when I know more. Permission is granted for everyone to use Rani Sharoni's auto_ptr implementation as you wish.

Thank you for all your replies.

A: 

Use boost::shared_ptr/boost::scoped_ptr. It will be the preferred smart pointer in upcoming C++ standards (is in TR1 already).

Edit: Please find a related discussion here: http://stackoverflow.com/questions/197048/idiomatic-use-of-stdautoptr-or-only-use-sharedptr

MP24
Preferred is a strong word. shared_ptr and auto_ptr do different things.
Martin York
Yes, that's true: I'd generally use the shared_ptr, but that may be due to the fact that I never had any use case for the auto_ptr.
MP24
I'm already following the other discussions about smart pointer here on stackoverflow, but thank you still. I'm already of the opinion that I would like to use auto, shared and scoped. But because of my compiler (and its library implementation), I'm not sure what to do.
Daniel Sönnerstedt
+1  A: 

Why do you think std::auto_ptr<> is broken.

I would have though that somthing as bad as that would have been reported to the standards comitte!

Do you mean that you need to:

std::auto_ptr<T>   x(new T);  // Use the explicit constructor.
Martin York
It is not broken everywhere. Just specifically in VC++ 8. VC++ 9 has a better implementation.
Daniel Sönnerstedt
Yes. Eitherstd::auto_ptr<T> x(new T);orstd::auto_ptr<T> x = std::auto_ptr<T>(new T);will work. std::auto_ptr<T> x = new T;shouldn't compile. It does and the result is undefined.
Daniel Sönnerstedt
What do you mean by “the results are undefined”? Shouldn't it just implicitly call the constructor? Of course this still is (arguably) a drawback.
Konrad Rudolph
Very interesting. I had not heard that before. Can you add that to your main question above so that it becomes part of the documentation.
Martin York
Konrad Rudolph:The results are not as much undefined as that the program crashes. An auto_ptr's operator= expects another auto_ptr. This was an actual bug I was dealing with today.Martin York:Added more info to my question.
Daniel Sönnerstedt
+2  A: 

Have you considered using STLPort?

OJ
That would be in line with the 'Replace the auto_ptr implementation' idea. I'm hoping I could do something a bit less than introducing a new STL implementation in our project. It is two years old and we are five people writing it. But thanks anyway.
Daniel Sönnerstedt
Technically replacing your STL implementation "shouldn't" cause you any issues. If anything it would remove then. But if you have code that relies on those issues then you're screwed. Considering it's a "drag and drop" solution, perhaps it's worth considering if you have the bandwidth for testing?
OJ
I second that. Replacing the STL should be a simple matter of configuring the project to use STLPort (which I believe uses the native STL were it is not broken).
Martin York
I'll have to investigate how much work it would involve to do this. It all just begun as an attempt to introduce everyone to smart pointers at work. Then I had a memory access bug, fortunately in our unit tests. No I have to convince everyone to replace their stl implementation...
Daniel Sönnerstedt
+2  A: 

Use a unique_ptr. I think these were introduced to be a better auto_ptr.

http://www.boost.org/doc/libs/1_35_0/doc/html/interprocess/interprocess_smart_ptr.html#interprocess.interprocess_smart_ptr.unique_ptr

In fact, I'm led to believe auto_ptr may be deprecated in favour of it:

http://objectmix.com/c/113487-std-auto_ptr-deprecated.html

Scott Langham
Boost has one available, although I'm not 100% sure what versions of VC have enough language standard conformance to be able to support it.
Scott Langham
Also, why is there only a boost::interprocess::unique_ptr and no boost::unique_ptr. I'd like to learn more before taking this path. The standard proposals for unique_ptr seems to only work on very standard compliant new compilers (gcc).
Daniel Sönnerstedt
Also, I think that deprecating auto_ptr would only be relevant once it is replaced by unique_ptr.
Daniel Sönnerstedt
Sorry, yes, I meant may be deprecated in the future. Yes, not sure why there's only an interprocess version... maybe this answer isn't fit now, but will probably become relevant in the future.
Scott Langham
Boost generally supports everything from VC7.1 (2003) up, though features may be limited for some libraries. VC8 and better will usually have all features supported.
Pavel Minaev
+7  A: 

Move to boost smart pointers.

In the meantime, you may want to extract a working auto_ptr implementation from an old / another STL, so you have working code.

I believe that auto_ptr semantics are fundamentally broken - it saves typing, but the interface actually is not simpler: you still have to track which instance is the current owner and make sure the owner leaves last.

unique-ptr "fixes" that, by making release not only give up ownership, but also setting the RHS to null. It is the closest replacement for auto-ptr, but with its different semantics it is not a drop-in replacement.

There's an introductory article to boost smart pointers, by, ahem, me.

peterchen
I read your article. It is very well written. Thank you. For most cases the boost pointers will be fine. I'm not sure at how I should deal with auto_ptr yet. I'm trying to establish a new guideline for smart pointers at work right now, so I'll better figure this out.
Daniel Sönnerstedt
Er, `auto_ptr` also sets RHS to null on any copy. That's how it gives up ownership!
Pavel Minaev
IIRC some (or the initial) implementations didn't.
peterchen
A: 

As far as I recall, wasn't it :

auto_ptr<T> x = auto_ptr<T>(new T()); ??
Maciek
That's overly lengthy - `auto_ptr<T> x(new T())` will do the same in a less roundabout way.
Pavel Minaev
A: 

Not an answer, but for general interest of anyone for whom these bugs are relevant. There's one more related bug with VC8's auto_ptr, which has to do with implicit upcasts. It's probably the most evil of the bunch, because other bugs just let you compile code that is otherwise illegal according to Standard without failing, but at least compliant code works fine. With this bug, the code that is actually compliant does not work properly.

The problem is this. Standard specifies auto_ptr constructors and conversion operators in such a way that they support implicit upcasting of auto_ptrs, just as with normal pointers. However, VC8 implementation of that does a reinterpret_cast rather than a static_cast there. Naturally, not only this is U.B. by the letter of the standard, but it also breaks with multiple base classes and/or virtual inheritance. Here's an example of legal code broken by this:

struct Base1 { int x; };
struct Base2 { int y; };
struct Derived : Base1, Base2 {};

std::auto_ptr<Derived> createDerived()
{
  return std::auto_ptr<Derived>(new Derived);
}

std::auto_ptr<Base2> base2(createDerived());

At one of my past jobs, when we ran into this problem in production, we ended up simply patching the headers ourselves (it's a trivial 2-line fix).

Pavel Minaev