zoukankan      html  css  js  c++  java
  • 智能指针

    前奏:

    Garbage Collection 技术一直颇受注目,并且在 Java 中已经发展成熟,成为内
    存管理的一大利器,但它在 C++ 语言中的发展却不顺利,C++ 为了追求运行速度,20 年来
    态度坚决地将其排除在标准之外。

    为了稍许平复因为没有 Garbage Collection 而引发的 C++ 程序员的怨气,C++
    对 Smart Pointer 技术采取了不同的态度。

    首先,了解一下智能指针,

    该方法使用一个指针类来代表对资源的管理逻辑,并将指向资源的句柄(指针
    或引用)通过构造函数传递给该类。当离开当前范围(scope)时,该对象的析构函数一定会
    被调用,所以嵌在析构函数中的资源回收的代码也总是会被执行。这种方法的好处在于,由
    于将资源回收的逻辑通过特定的类从原代码中剥离出来,自动正确地销毁动态分配的对象,
    这会让思路变得更加清晰,同时确保内存不发生泄露。

    它的一种通用实现技术是使用引用计数(Reference Count) 。引用计数智能指针,是一
    种生命期受管的对象,其内部有一个引用计数器。当内部引用计数为零时,这些对象会自动
    销毁自身的智能指针类。每次创建类的新对象时,会初始化指针并将引用计数置为 1 ;当对
    象作为另一对象的副本而创建时,它会调用拷贝构造函数拷贝指针并增加与之相应的引用计
    数 ;对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数 ;如果引用计数
    减至 0,则删除对象,并增加右操作数所指对象的引用计数 ;调用析构函数时,构造函数减
    少引用计数,直到计数为 0,释放对象空间。

    其次,auto_ptr包含在#include <memory>

    auto_ptr 可以指向一个以 new 建立的对象,当 auto_ptr 的生命周期结束时,其所指向的
    对象之资源也会被自动释放,且不必显式地调用 delete,而对象指针的操作依旧如故。例如:
    class A
    {
    public:
    A(){}
    ~A(){}
    void Hello()

    {
    std::cout<<"Hello Smart Pointer";
    }
    };
    int main()
    {
    std::auto_ptr<A> pA(new A());
    pA->Hello();
    return 0;
    }
    当然,也可以建立一个未指向任何对象的 auto_prt,例如:
    std::auto_ptr<int> iPtr;
    它就像空指针,未指向任何对象,所以也就不能进行操作,但是可以通过 get() 函数来
    判断它是否指向对象的地址
    if(iPtr.get() == 0) // 不指向任何对象
    {
    iPtr.reset(new int(2011)); // 指向一个对象
    }
    auto_ptr 还可以使用另一个 auto_ptr 来建立,但是需要十分小心的是,这会造成所有权
    的转移,例如:
    auto_ptr< string> sPtr1 (new string("Smart Pointer"));
    auto_ptr< string> sPtr2 (sPtr1);
    if( !sPtr1->empty() )
    cout<<*sPtr1<< endl;
    当使用 sPtr1 来建立 sPtr2 时,sPtr1 不再对所指向对象的资源释放负责,而是将接力
    棒传递到了 sPtr2 的手里,sPtr1 丧失了使用 string 类成员函数的权利,所以在判断 sPtr1-
    >empty() 时程序会崩溃。
    auto_ptr 的资源维护动作是以 inline 的方式来完成的,在编译时代码会被扩展开来,所
    以使用它并不会牺牲效率。虽然 auto_ptr 指针是一个 RAII (Resource Acquisition In Initialization)对象,能够给我们带来很多便利,
    但是它的缺点同样不可小觑:

    auto_ptr 对象不可作为 STL 容器的元素,所以二者带来的便利不能同时拥有。这一重
    大缺陷让 STL 的忠实拥趸们愤怒不已。
    auto_ptr 缺少对动态配置而来的数组的支持,如果用它来管理这些数组,结果是可怕
    的、不可预期的。
    auto_ptr 在被复制的时候会发生所有权转移

    就在 2011 年的 9 月刚刚获得通过的 C++ 新标
    准 C++ 11 中废弃了 auto_ptr 指针,取而代之的是两个新的指针类:shared_ptr 和 unique_ptr
    shared_ptr 只是单纯的引用计数指针,unique_ptr 是用来取代 auto_ptr 的。unique_ptr 提供了
    auto_ptr 的大部分特性,唯一的例外是 auto_ptr 的不安全、隐性的左值搬移 ;而 unique_ptr
    可以存放在 C++0x 提出的那些能察觉搬移动作的容器之中。

    在 Boost 中的智能指针共有五种 :scoped_ptr、scoped_array、shared_ptr、shared_array、
    weak_ptr,其中最有用的就是 shared_ptr,它采取了引用计数,并且是线程安全的,同时支
    持扩展,推荐在大多数情况下使用。

    boost::shared_ptr 支持 STL 容器:
    typedef boost::shared_ptr<string> CStringPtr;
    std::vector< CStringPtr > strVec;
    strVec.push_back( CStringPtr(new string("Hello")) );

    当 vector 被销毁时,其元素 — 智能指针对象才会被销毁,除非这个对象被其他的智能
    指针引用,如下面的代码片段所示:
    typedef boost::shared_ptr<string> CStringPtr;
    std::vector< CStringPtr > strVec;
    strVec.push_back( CStringPtr(new string("Hello")) );
    strVec.push_back( CStringPtr(new string("Smart")) );
    strVec.push_back( CStringPtr(new string("Pointer")) );
    CStringPtr strPtr = strVec[0];
    strVec.clear(); //strVec 清空,但是保留了 strPtr 引用的 strVec[0]
    cout<<*strPtr<<endl; // strVec[0] 依然有效

    Boost 智能指针同样支持数组,boost::scoped_array 和 boost::shared_array 对象指向的是
    动态配置的数组。
    Boost 的智能指针虽然增强了安全性,处理了潜在的危险,但是我们在使用时还是应该
    遵守一定的规则,以确保代码更加鲁棒。

    规则 1:Smart_ptr<T> 不同于 T*
    Smart_ptr<T> 的真实身份其实是一个对象,一个管理动态配置对象的对象,而 T* 是指
    向 T 类型对象的一个指针,所以不能盲目地将一个 T* 和一个智能指针类型 Smart_ptr<T> 相
    互转换。
    在创建一个智能指针的时候需要明确写出 Smart_ptr<T> tPtr<new T>。
    禁止将 T* 赋值给一个智能指针。

    不能采用 tPtr = NULL 的方式将 tPtr 置空,应该使用智能指针类的成员函数。

    规则 2:不要使用临时的 share_ptr 对象

    class A;
    bool IsAllReady();
    void ProcessObject(boost::shared_ptr< A> pA, bool isReady);
    ProcessObject(boost::shared_ptr(new A), IsAllReady());
    调用 ProcessObject 函数之前,C++ 编译器必须完成三件事:
    (1) 执行 "new A"。
    (2) 调用 boost::shared_ptr 的构造函数。
    (3) 调用函数 IsAllReady()。
    因为函数参数求值顺序的不确定性,如果调用 IsAllReady() 发生在另外两个过程中间,
    而它又正好出现了异常,那么 new A 得到的内存返回的指针就会丢失,进而发生内存泄露,
    因为返回的指针没有被存入我们期望能阻止资源泄漏的 boost::shared_ptr 上。避免出现这种
    问题的方式就是不要使用临时的 share_ptr 对象,改用一个局部变量来实现在一个独立的语
    句中将通过 new 创建出来的对象存入智能指针中:

    boost::shared_ptr<A> pA(new A)
    ProcessObject(pA, IsAllReady());
    如果疏忽了这一点,当异常发生时,可能会引起微妙的资源泄漏。

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <stdlib.h>
     4 #include <string.h>
     5 #include <vector>
     6 #include <time.h>
     7 #include <assert.h>
     8 #include <memory>
     9 #include <signal.h>
    10 using namespace std;
    11 
    12 int main(){
    13     shared_ptr<int> p(new int(4));
    14     shared_ptr<int> p2 = make_shared<int>(4);
    15     cout << *p << " ";
    16     unique_ptr<int> p3(new int(4));
    17     cout << *p3 << " ";
    18     return 0;
    19 }
  • 相关阅读:
    与众不同 windows phone (50)
    与众不同 windows phone (49)
    重新想象 Windows 8.1 Store Apps (93)
    重新想象 Windows 8.1 Store Apps 系列文章索引
    重新想象 Windows 8.1 Store Apps (92)
    重新想象 Windows 8.1 Store Apps (91)
    重新想象 Windows 8.1 Store Apps (90)
    重新想象 Windows 8.1 Store Apps (89)
    重新想象 Windows 8.1 Store Apps (88)
    重新想象 Windows 8.1 Store Apps (87)
  • 原文地址:https://www.cnblogs.com/guxuanqing/p/4805054.html
Copyright © 2011-2022 走看看