Почему vector.push_back (auto_ptr) не скомпилируется? - PullRequest
6 голосов
/ 09 сентября 2011

Я узнал, что STL может запретить программисту помещать auto_ptr в контейнер.Например, следующий код не будет компилироваться:

    auto_ptr<int> a(new int(10));
    vector<auto_ptr<int> > v;
    v.push_back(a);

auto_ptr имеет конструктор копирования, почему этот код может даже компилироваться?

Ответы [ 4 ]

11 голосов
/ 09 сентября 2011

Глядя на определение std::auto_ptr:

namespace std {

    template <class Y> struct auto_ptr_ref {};


    template <class X>
    class auto_ptr {
    public:
        typedef X element_type;

        // 20.4.5.1 construct/copy/destroy:
        explicit           auto_ptr(X* p =0) throw();
                           auto_ptr(auto_ptr&) throw();
        template <class Y> auto_ptr(auto_ptr<Y>&) throw();

        auto_ptr&                      operator=(auto_ptr&) throw();
        template <class Y> auto_ptr&   operator=(auto_ptr<Y>&) throw();
        auto_ptr&                      operator=(auto_ptr_ref<X>) throw();

        ~auto_ptr() throw();

        // 20.4.5.2 members:
        X&     operator*() const throw();
        X*     operator->() const throw();
        X*     get() const throw();
        X*     release() throw();
        void   reset(X* p =0) throw();

        // 20.4.5.3 conversions:
                                    auto_ptr(auto_ptr_ref<X>) throw();
        template <class Y> operator auto_ptr_ref<Y>() throw();
        template <class Y> operator auto_ptr<Y>() throw();
    };

}

Хотя существует конструктор копирования, он принимает ссылку на non- const. Временные могут не связываться с этим, поэтому типу фактически запрещено работать внутри контейнеров в любом месте, где используются временные; кроме того, push_back принимает ссылку на const, поэтому из-за правильности const новый внутренний элемент не может быть создан путем копирования из аргумента push_back.

(Эта страница в Википедии гласит, что «из-за своей семантики копирования auto_ptr не может использоваться в контейнерах STL, которые могут выполнять копирование элементов в своих операциях»; это не означает, что контейнеры волшебным образом проверяют код внутри конструктора копирования для решить, хочет ли он заставить тип работать как тип элемента. Вместо этого речь идет только о сигнатуре функции.)

В любом случае, std::auto_ptr устарела с C ++ 11, потому что, по мнению некоторых, std::auto_ptr глупо. Извините, std::auto_ptr.

6 голосов
/ 09 сентября 2011

По конкретному вопросу о том, как компилятор обнаруживает эту ситуацию (или как STL вызывает там ошибку), вы должны прочитать точный вывод компилятора, он будет содержать кучу ошибок, которые приведут к ошибке.выполнить преобразование из const X в X, поскольку оно отбрасывает квалификатор const, где X может быть либо std::auto_ptr<> напрямую, либо внутренним типом детализации.

В частности, std::vector::push_back принимаетаргумент const &, и внутри он попытается скопировать конструкцию элемента внутри динамического массива, используя доступный конструктор копирования, который в случае std::auto_ptr требует неконстантной ссылки.Что-то в строках:

void push_back( std::auto_ptr<int> const & x ) {
    // ensure enough capacity if needed...
    new (buffer + size()) std::auto_ptr<int>( x ); // !!! cannot bind x to non-const&
    // complete the operation (adjust end pointer, and such)
}
0 голосов
/ 09 сентября 2011

Другие ответы касаются auto_ptr.

Чтобы сделать то, что вы пытаетесь сделать, используйте std :: unique_ptr, если он вам доступен (C ++ 11), если нет, вы можете использовать shared_ptr

0 голосов
/ 09 сентября 2011

Поскольку std :: auto_ptr несовместим с контейнером stl.

std :: auto_ptr использует семантику копирования с одним владельцем, контейнер stl должен копировать конструкцию объекта (и некоторые алгоритмы должны назначать его)

Вы должны использовать умный указатель с подсчетом ссылок (boost :: shared_ptr)

EDIT

Например, это подпись push_back

void push_back ( const T& x );

Проблема в том, что std :: auto_ptr является специальным, а конструктор копирования и подпись оператора присваивания различаются. Они НЕ постоянны. Вы изменяете auto_ptr, если копируете его.

auto_ptr& operator= (auto_ptr& a) throw();

auto_ptr (auto_ptr& a) throw();

Вы не можете предоставить auto_ptr, который удовлетворяет требованию push_back.

...