views:

147

answers:

4

Could somebody please explain why I'm getting a compile error here - error C2558: class 'std::auto_ptr<_Ty>' : no copy constructor available or copy constructor is declared 'explicit'

#include <memory>
#include <vector>
#include <string>
template<typename T>
struct test
{
    typedef std::auto_ptr<T> dataptr;
    typedef std::auto_ptr< test<T> > testptr;
    test( const T& data ):
    data_( new T(data) )
    {
    };
    void add_other( const T& other )
    {
        others_.push_back( testptr( new test(other) ) );
    }
private:
    dataptr data_;
    std::vector< testptr > others_;
};

int main(int argc, char* argv[])
{
    test<std::string> g("d");

    //this is the line that causes the error.
    g.add_other("d");

    return 0;
}
+6  A: 
    others_.push_back( testptr( new test(other) ) );

You are trying to push an auto_ptr into a std::vector

auto_ptr does not define an implicit copy constructor and is not compatible as a value in the stl container classes.

See this question for more info: StackOverflow: Why is it wrong to use stdauto ptr with stl containers

Akusete
+4  A: 

You cannot create standard library containers of auto_ptr, as you are trying to do here:

std::vector< testptr > others_;

as they do not have the correct semantics. You will have to use ordinary pointers or a different flavour of smart pointer, such as shared_ptr.

anon
+3  A: 

Basically a std::auto_ptr cannot be used in this way.

others_.push_back( testptr( new test(other) ) );

Requires that a copy constructor that takes a const& exists and no such constructor exists for std::auto_ptr. This is widely viewed as a good thing since you should never use std::auto_ptr in a container! If you do not understand why this is, then read this article by Herb Sutter, particularly the section entitled "Things Not To Do, and Why Not To Do Them" about 3/4 of the way through.

D.Shawley
If the standard containers were mandated to use `swap` to copy things around, auto_ptr would work. And I really wish they were. In C++0x, `::std::unique_ptr` (which is very much like `::std::auto_ptr`) also does not have a copy contructor, and only has a move constructor, and the standard containers are mandated to use the move constructor to move their contents around, so you can store `::std::unique_ptr` in them and have it work as expected.
Omnifarious
In fact, it's illegal to use `auto_ptr` in a container because STL containers require that their members have "normal" copying behavior. Auto_ptr doesn't meet that requirement.
Billy ONeal
@Omnifarious: You're mixing shared_ptr with unique_ptr. Shared_ptr is a reference counted smart pointer, not one with move semantics.
Billy ONeal
@Billy - Do the code police come and take you away if you do it, or does it simply result in a compiler error? Oh! And you're right about `shared_ptr`. I'll fix that now.
Omnifarious
@Omnifarious: It's *supposed* to be a compile time error. Not all compilers do it though. For compilers where it is not a compile time error, it is undefined behavior. You couldn't do this even if you had something like `swap` based innards for those containers, because standard algorithms would still screw things up (they expect to be able to copy with impunity)
Billy ONeal
@Billy ONeal - I disagree about the 'swap based innards' thing because I am proposing above that the standard containers be required to use 'swap' instead of copying to move data around and that they never copy it. This is clearly possible as they do exactly that in C++0x. I think this behavior requirement should've been part of their original spec, and that the fact they don't do this is a spec bug. But it's too late to fix with a 'minor revision' now, so we'll have to wait for C++0x to be widely implemented.
Omnifarious
@Omnifarious: Err.. how would you build your container exactly so that any arbitrary operation on it's iterators would always use swap semantics? You could do it for storage reallocations, but not in the general case.
Billy ONeal
@Omni: See Effective STL Item 8 for more details.
Billy ONeal
+2  A: 

You probably want std::unique_ptr or std::shared_ptr from the upcoming C++0x standard which will replace auto_ptr if you have access to a compiler that has these implemented (gcc 4.5+)

http://www2.research.att.com/~bs/C++0xFAQ.html#std-unique_ptr http://www2.research.att.com/~bs/C++0xFAQ.html#std-shared_ptr

David