智能指针(smart pointer)

智能指针(smart pointer)是一种抽象的数据类型(abstract data type)。 在程序设计中, 智能指针通常由类模板(class template)实现,。 通常借助模板达到泛型,借助类的析构函数来达成自动释放指针所指向的内存或者对象。 

智能指针模拟了指针的所有的属性, 然后在加上指针没有的额外的features, 这些features包括自动内存管理(automatic memory mangement), 或者bouds checking。 之所以加上这些特性, 是因为这些额外的特性具有很多好的作用, 能够减少因为使用指针不当而造成的bugs, 并且保持高效型。

Misuse of pointers通常是造成bugs的主要的源头所在。 使用智能指针的自动内存回收机制(automatic memory deallocation)能够避免出现内存泄露(memory leaks)。 更一般的, 他们能够进行对象的自动析构:当对象的最后一个owner(即智能指针)被destroyed的时候,  智能指针的控制着(或者拥有的)的对象就可以自动被destroyed。   举个例子, 如果对象的owner(智能指针)是一个local variable的时候, 当execution运行到智能指针的scope之外的时候, 那么智能指针指向的对象也能够自动destroyed了。 智能指针通过推迟对象的destruction, 直至object不再被使用, 才进行对象的析构, 这样就不会再有dangling pointers了。 这也就不需要我们手动的去delete了。

智能指针有很多种:

1) 一些智能指针有reference counting(引用计数)的机制(shared_ptr)。 这很节省内存。 Linux里面管理文件Inode就是采用的引用计数的机制。

(2)一些智能指针通过对ownership of an object进行赋值(unique_ptr)。  这个对象只能一次被一个指针指向

C++的智能指针是通过模板了类实现的。 利用operator overloading的方式, 这样智能指针就具有了除了原始指针(raw pointer)的一些behavior(例如dereference, assignment)之外, 还提供额外的内存管理特征(memory management features)。

C++11中提供了std::unique_ptr, 定义在<memory>头文件中。 std::unique_ptr替代了原先的std::auto_ptr, 也就是auto_ptr是deprecated, 基本上现在最后不用auto_ptr

C++11新增了move语义。 相比于copy语义, move能更好的实现值传递。 std::auto_ptr使用的是copy语义。 为了先前兼容, C++11没有修改std::auto_ptr, 而是引入了新的使用move语义的std::unique_ptr

auto_ptr(现在已经不再用了)不能作为容器(例如vector)的元素, 而unique_ptr可以作为容器的元素

unique_ptr的拷贝构造函数和赋值运算符都声明为deleted。 也就是说它不能被拷贝, 只能通过std::move来传递它指向的内存的所有权。 下面的例子说的很清楚:

<span style="font-size:14px;">std::unique_ptr<int> p1(new int(5)); // new int(5)在heap中分配一个能存一个int的内存, p1指向这个int的对象
std::unique_ptr<int> p2 = p1; // 编译会出错, 即对unique_ptr不能拷贝构造和赋值, 因为赋值运算符被声明ideleted
std::unique_ptr<int> p3 = std::move(p1); // move了, 转移所有权, 现在那块内存归p3所有, p1成为无效的指针. 
 
p3.reset(); //释放内存.
p1.reset(); //实际上什么都没做.</span>

使用unique_ptr的一个例子:

<span style="font-size:14px;">#include <iostream>
#include <memory>

struct Foo {
    Foo() { std::cout << "Foo::Foo\n"; }
    ~Foo() { std::cout << "Foo::~Foo\n"; }
    void bar() { std::cout << "Foo::bar\n"; }
};

void f(const Foo &foo)
{
    std::cout << "f(const Foo&)\n";
}

int main()
{
    std::unique_ptr<Foo> p1(new Foo);  // p1 owns Foo
    if (p1) p1->bar();
    {
        std::unique_ptr<Foo> p2(std::move(p1));  // now p2 owns Foo, p1对对象没有ownership
        f(*p2);

        p1 = std::move(p2);  // ownership returns to p1
        std::cout << "destroying p2...\n";
    }

    if (p1) p1->bar();

    // Foo instance is destroyed when p1 goes out of scope
}</span>

运行结果如下:


std::auto_ptr 依然存在, 但在C++11中被标为"弃用"。

shared_ptr和weak_ptr

定义在头文件<memory>中。

基于Boost库, C++引入了另外两个智能shared_ptr和weak_ptr。 他们最早在TR1中引入, 但是在C++11中, 在Boost的基础上又加入了新的功能。

std::shared_ptr使用的是引用计数(reference counting)。 每一个shared_ptr的拷贝都指向相同的内存。 在最后一个shared_ptr析构的时候, 内存才会被释放(当引用计数变成0了)。

<span style="font-size:14px;">std::shared_ptr<int> p1(new int(5));
std::shared_ptr<int> p2 = p1; // 都指向同一内存.
 
p1.reset(); // 因为p2还在,所以内存没有释放. 也就是说int(5)还存在着
p2.reset(); // 释放内存, 因为没有shared_ptr指向那块内存了(即reset后, 引用计数变成0了). 即int(5)那块内存被回收了</span>

关于shared_ptr的reset函数:

原型: 

void reset();
(1) (since C++11)
template< class Y > 
void reset( Y* ptr );
(2) (since C++11)
template< class Y, class Deleter > 
void reset( Y* ptr, Deleter d );
(3) (since C++11)
template< class Y, class Deleter, class Alloc > 
void reset( Y* ptr, Deleter d, Alloc alloc );
(4) (since C++11)
作用:

For signature (1) the object becomes empty (as if default-constructed).

In all other cases, the shared_ptr acquires ownership of p with a use count of 1, and -optionally- with del and/oralloc as deleter and allocator, respectively.

Additionally, a call to this function has the same side effects as if shared_ptr's destructor was called before its value changed (including the deletion

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值