[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标准之前,这真是悲剧——唯一的智能指针却几乎木有勇武之地~




posted @ 2012-04-27 13:19  斯啦丝拉  阅读(5167)  评论(0编辑  收藏  举报