现代C++的智能指针

    为了更加高效安全的使用指针,智能指针应运而生。

1. unique_ptr (原auto_ptr,由于不够高效,已被否决):动态分配对象以及当对象不再需要时自动执行清理,并且指针无法复制,只能通过std::move移动;

    auto ptrA = unique_ptr<Song>(new Song(L"T", L"A"));

    auto ptrB = ptrA;    // wrong!!!

    auto ptrC = std::move(ptrA);   // right!!!

2. shared_ptr:引用计数智能指针,一个原始指针被多个所有者引用,大多用于多线程编程中;

    (1) 删除共享对象

使用shared_ptr解决的主要问题是知道删除一个被多个客户共享的资源的正确时机。下面是一个简单易懂的例子,有两个类 A和 B, 它们共享一个int实例。使用 boost::shared_ptr,你需要必须包含 "boost/shared_ptr.hpp".

#include "boost/shared_ptr.hpp"

#include <cassert>

class A {

boost::shared_ptr<int> no_;

public:

A(boost::shared_ptr<int> no) : no_(no) {}

void value(int i) {

*no_=i;

}

};

class B {

boost::shared_ptr<int> no_;

public:

B(boost::shared_ptr<int> no) : no_(no) {}

int value() const {

return *no_;

}

};

int main() {

boost::shared_ptr<int> temp(new int(14));

A a(temp);

B b(temp);

a.value(28);

assert(b.value()==28);

} 类 A和 B都保存了一个 shared_ptr<int>. 在创建 A和 B的实例时,shared_ptr temp被传送到它们的 构造函数。这意味着共有三个  shared_ptr:a, b, 和 temp,它们都引向同一个int实例。如果我们用 指针来实现对一个的共享,A和 B必须能够在某个时间指出这个int要被删除。在这个例子中,直到main的结束, 引用计数为3,当所有  shared_ptr离开了作用域,计数将达到0,而最后一个 智能指针将负责删除共享的 int.


    (2) 标准容器使用


        把对象直接存入容器中有时会有些麻烦。以值的方式保存对象意味着使用者将获得容器中的元素的拷贝,对于那些复制是一种昂贵的操作的类型来说可能会有性能的问题。此外,有些容器,特别是 std::vector, 当你加入元素时可能会复制所有元素,这更加重了性能的问题。最后,传值的语义意味着没有多态的行为。如果你需要在容器中存放多态的对象而且你不想切割它们,你必须用指针。如果你用裸指针,维护元素的完整性会非常复杂。从容器中删除元素时,你必须知道容器的使用者是否还在引用那些要删除的元素,不用担心多个使用者使用同一个元素。这些问题都可以用shared_ptr来解决。

下面是如何把共享指针存入标准库容器的例子。

#include "boost/shared_ptr.hpp"

#include <vector>

#include <iostream>

class A {

public:

virtual void sing()=0;

protected:

virtual ~A() {};

};

class B : public A {

public:

virtual void sing() {

std::cout << "Do re mi fa so la";

}

};

boost::shared_ptr<A> createA() {

boost::shared_ptr<A> p(new B());

return p;

}

int main() {

typedef std::vector<boost::shared_ptr<A> >container_type;

typedef container_type::iterator iterator;

container_type container;

for (int i=0;i<10;++i) {

container.push_back(createA());

}

std::cout << "The choir is gathered: \n";

iterator end=container.end();

for (iterator it=container.begin();it!=end;++it) {

(*it)->sing();

}

} 这里有两个类, A和 B, 各有一个虚拟成员函数 sing. B从 A公有继承而来,并且如你所见,工厂函数 createA返回一个动态分配的B的实例,包装在shared_ptr<A>里。在 main里, 一个包含shared_ptr<A>的 std::vector被放入10个元素,最后对每个元素调用sing。如果我们用裸指针作为元素,那些对象需要被手工删除。而在这个例子里,删除是自动的,因为在vector的生存期中,每个shared_ptr引用计数都保持为1;当 vector被销毁,所有引用计数器都将变为零,所有对象都被删除。有趣的是,即使 A的析构函数没有声明为 virtual, shared_ptr也会正确调用 B的析构函数!

上面的例子示范了一个强有力的技术,它涉及A里面的protected析构函数。因为函数 createA返回的是 shared_ptr<A>, 因此不可能对shared_ptr::get返回的指针调用 delete。这意味着如果为了向某个需要裸指针的函数传送裸指针而从shared_ptr中取出裸指针的话,它不会由于意外地被删除而导致灾难。那么,又是如何允许 shared_ptr删除它的对象的呢? 这是因为指针指向的真正类型是 B; 而B的析构函数不是protected的。这是非常有用的方法,用于给shared_ptr中的对象增加额外的安全性。


3. weak_ptr:在使用引用计数智能指针时,如果需要访问指针数据,却不想参与引用计数时,可以使用弱指针;


              shared_ptr<int> sp(new int(10)); // 一个shared_ptr

              assert(sp.use_count() == 1);

              weak_ptr<int> wp(sp); // 从shared_ptr创建weak_ptr

              assert(wp.use_count() == 1); // weak_ptr不影响引用计数

              if (!wp.expired()) // 判断weak_ptr观察的对象是否失效

              {

                   shared_ptr<int> sp2 = wp.lock(); // 获得一个shared_ptr

                   *sp2 = 100;

                   assert(wp.use_count() == 2);

              } // 退出作用域,sp2自动析构,引用计数减1

             assert(wp.use_count() == 1);

             sp.reset(); // shared_ptr失效

             assert(wp.expired());

             assert(!wp.lock()); // weak_ptr将获得一个空指针



参考:

      http://technet.microsoft.com/zh-cn/subscriptions/hh279676

      http://baike.baidu.com/view/2276295.htm

      http://www1.huachu.com.cn/read/readbookinfo.asp?sectionid=1000005016



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值