2011-09-09 81 views
6

我了解到STL可以禁止程序员将auto_ptr放入容器中。例如下面的代码不会编译:为什么vector.push_back(auto_ptr)不能编译?

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

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

+1

我知道我不应该在stl中使用auto_ptr,因为复制语义。但我的问题是** stl是如何实现的,所以它可以禁止你这样做?**在我的示例代码中,它甚至不能编译。 – frinker

+1

你可以发布编译错误吗? –

+0

@xanatos:没有拷贝构造函数是'const'! –

回答

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容器中使用”;这并不意味着容器会奇迹般地检查拷贝构造函数中的代码决定是否希望使工作类型为元素的类型。相反,它只是函数签名。)

反正std::auto_ptr被弃用的C++ 11,因为,在一些人看来,std::auto_ptr是愚蠢。对不起,std::auto_ptr

+0

+1,这里也讨论了:http://stackoverflow.com/q/3316514 – sharptooth

+1

我强烈反对,std :: auto_ptr是解决一组问题的完美选择。可悲的是开发者滥用它。 –

+0

+1,我明白了,谢谢你! – frinker

0

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

的std :: auto_ptr的是使用单一所有权拷贝语义的STL容器需要拷贝构造一个对象(和一些算法需要指定它)

您应该使用计数智能指针的引用(升压:: 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(); 

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

+0

或者像'std :: unique_ptr'这样的具有移动语义的体面的单一所有权指针。 –

+0

查看Effective C++的项目13-17,它不是专用于auto_ptr,但它对了解您的问题非常有用。 –

+3

我知道我不应该在stl中使用auto_ptr,因为复制语义。但我的问题是** stl是如何实现的,所以它可以禁止你这样做?**在我的示例代码中,它甚至不能编译。 – frinker

0

其他答案是关于auto_ptr爆炸。

做你正在尝试做的使用std ::的unique_ptr如果提供给你(C++ 11),如果不是,你可以使用一个shared_ptr

6

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

特别地,通过std::vector::push_backconst &取参数,并在内部将尝试复制构建使用可用的拷贝构造,这在std::auto_ptr的情况下需要非const引用动态数组中的元素。行内的东西:

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) 
}