为什么vector.push_back(auto_ptr)不能编译?

时间:2011-09-09 08:56:26

标签: c++ stl auto-ptr

我了解到STL可以禁止程序员将auto_ptr放入容器中。例如,以下代码无法编译:

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

auto_ptr有复制构造函数,为什么这段代码甚至可以编译?

4 个答案:

答案 0 :(得分:11)

查看the definition of 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();
    };

}

虽然有复制构造函数,但它需要引用非 - const 。临时工具可能不会与此绑定,因此在任何使用临时工位的地方,有效禁止该类型在集装箱内工作;此外,push_back接受对const的引用,因此由于const - 正确性,新的内部元素不可能通过push_back的参数进行复制构造

(维基百科页面说“由于其复制语义,auto_ptr可能不会在可能在其操作中执行元素副本的STL容器中使用”;这并不意味着容器会神奇地检查复制构造函数中的代码决定是否要将类型作为元素类型工作。相反,它只是函数签名。)

无论如何,从C ++ 11开始,std::auto_ptr已被弃用,因为有些人认为std::auto_ptr是愚蠢的。对不起,std::auto_ptr

答案 1 :(得分:6)

关于编译器如何检测这种情况(或者STL如何在那里导致错误)的特定问题,你应该读取编译器的确切输出,它将包含一堆错误,这些错误将导致失败执行从const XX的转换,因为它会丢弃const限定符,其中X可以是std::auto_ptr<>,也可以是内部详细信息类型。

特别地,std::vector::push_back接受const &的参数,并且在内部它将尝试使用可用的复制构造函数复制构造动态数组内的元素,在{{1}的情况下需要一个非const引用。有些东西:

std::auto_ptr

答案 2 :(得分:0)

因为std :: auto_ptr与stl容器不兼容。

std :: auto_ptr使用单一所有权复制语义,stl容器需要复制构造一个对象(有些算法需要分配它)

您应该使用引用计数智能指针(boost :: shared_ptr)

修改

例如,这是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();

您无法提供满足push_back要求的auto_ptr。

答案 3 :(得分:0)

关于auto_ptr的其他答案很明显。

要执行您要执行的操作,请使用std :: unique_ptr(如果可用)(C ++ 11),否则可以使用shared_ptr