[C++][STL]智能指针:auto_ptr
现在,C++有如下智能指针,除了auto_ptr外,其他都是11标准引入的。所有的智能指针都是模板化(class template)的。so,可以使用xxxx_ptr<T>的形式来满足不同的数据类型。
unique_ptr
smart pointer with unique object ownership semantics
只能有一个主人的指针,可以用于STL容器
shared_ptr
smart pointer with shared object ownership semantics
可共享的指针
weak_ptr
weak reference to an object managed by std::shared_ptr
弱引用指针
auto_ptr
smart pointer with strict object ownership semantics
只能有一个主人的指针,不能用于STL容器
auto_ptr
auto_ptr具有如下的特点:
退出生存期后,自动销毁。
不能指向数组,这是因为其内部实现,在析构函数里执行了delete ptr,而不是delete[] ptr。
不可能存在多个auto_ptr指向同一个对象。这是最重要的。也就是说,auto_ptr不能用作STL容器的元素。
主要由于上边这个原因,auto_ptr在C++11中已经被废弃了(虽然仍然可以使用它),推荐用unique_ptr取代之。
下边举例说明
创建一个auto_ptr
// 访问空的auto_ptr会出错 auto_ptr<int> p; cout << *p << endl; // 想模仿int* p = 5也是不行的,编译不过 // auto_ptr的operator=被重载,不是简单的赋值了。 // 不能使用=来初始化,除非对象是auto_ptr auto_ptr<int> p = 5; // 直接使用auto_ptr的构造函数赋初值也是不成的,因为初值必须是指针地址。 // 编译报错 auto_ptr<int> p(5); // 可以使用地址,通过构造函数来初始化 // 不过这么搞,也就失去了其用途了:为的就是防止出现指针,结果还额外多出来个指针。 int i = 5; int* p = &i; auto_ptr<int> auto_p(p); cout << *auto_p << endl; // 只要是类型正确的指针就可以,并不验证数据有效性,只要够风骚~ int i = -10; unsigned* p = (unsigned*)&i; auto_ptr<unsigned> auto_p(p); cout << *auto_p << endl; // 输出一个好大的数,因为unsigned不考虑符号位嘛
正确的方法是这样,在构造函数的参数里使用new。这是唯一推荐的方法。这样,等auto_ptr销毁了,保存的数据的内存也会释放。
// 唯一的推荐方法 auto_ptr<unsigned> auto_p(new unsigned(10));
也可以创建一个NULL的auto_ptr对象,然后用operator=“赋值”,右值必须也是auto_ptr对象。
这里的等号不是真正的赋值,同时会让原始的auto_ptr无效化。
auto_ptr<unsigned> auto_p1(new unsigned(10)); // 先创建了一个空的auto_ptr,然后从其他auto_ptr处获得所有权 auto_ptr<unsigned> auto_p2;
auto_p2 = auto_p1;
也可以直接在构造函数里传递所有权,效果类似。
auto_ptr<unsigned> auto_p1(new unsigned(10)); auto_ptr<unsigned> auto_p2(auto_p1);
对象只有一个auto_ptr的主人
参考上边的三条语句,会发现对象所有权的转移。
第一条语句执行后:auto_p1完成初始化,auto_p2还未创建。此时10的所有者是auto_p1
第二条语句执行后:auto_p2完成“初始化”,此时auto_p2是一个空对象。
第三条语句执行后:auto_p2被赋值,但是auto_p1却变成了空值。
这样的原因是auto_ptr重载了operator=,其实现类似于:
template<class T1> class auto_ptr { template<class T2> auto_ptr<T1>& operator=(auto_ptr<T2>& Right) throw()() { // assign compatible _Right (assume pointer) // 等号右边的auto_ptr,其ptr值传到左边的auto_ptr,原始值置为0 T2* tmp = Right.ptr; Right.ptr = 0; if (tmp != this.ptr) delete ptr; this.ptr = tmp; return (*this); } }
因为所有权的转移,所以auto_ptr不能用于STL容器的成员,在11标准之前,这真是悲剧——唯一的智能指针却几乎木有勇武之地~