为什么vector.push_back(auto_ptr)不会编译?
Why vector.push_back(auto_ptr) wouldn't compile?
我了解到STL可以禁止程序员将auto_ptr放入容器中。例如,下面的代码不能编译:
auto_ptr<int> a(new int(10));
vector<auto_ptr<int> > v;
v.push_back(a);
auto_ptr有复制构造函数,为什么这段代码甚至可以编译?
看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
关于编译器如何检测这种情况的特定问题(或STL如何在那里引起错误),您应该阅读编译器的确切输出,它将包含一堆错误,这些错误将导致无法执行从const X
到X
的转换,因为它丢弃了const限定符,其中X
可以直接为std::auto_ptr<>
或其他内部细节类型。
特别地,std::vector::push_back
接受const &
的实参,并在内部尝试使用可用的复制构造函数在动态数组中复制构造一个元素,在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)
}
其他答案都是关于auto_ptr的。
如果std::unique_ptr可用(c++ 11),则可以使用shared_ptr因为std::auto_ptr与stl容器不兼容
std::auto_ptr使用单所有权复制语义,STL容器需要复制构造对象(并且某些算法需要为其赋值)
你应该使用引用计数的智能指针(boost::shared_ptr)
编辑
例如,这是push_back 的签名void push_back ( const T& x );
问题在于std::auto_ptr是特殊的,复制构造函数和赋值操作符签名是不同的。它们不是const。如果复制auto_ptr,则修改auto_ptr。
auto_ptr& operator= (auto_ptr& a) throw();
auto_ptr (auto_ptr& a) throw();
不能提供满足push_back要求的auto_ptr。