码迷,mamicode.com
首页 > 其他好文 > 详细

智能指针简介

时间:2017-09-07 23:04:14      阅读:223      评论:0      收藏:0      [点我收藏+]

标签:引用   erase   false   direct   smart   use   error   cat   operator   

         智能指针用于解决常规指针所带来的内存泄露、重复释放、野指针等内存问题。智能指针基于这样的事实得以发挥作用:定义在栈中的智能指针,当超出其作用域时,会自动调用它的析构函数,从而可以释放其关联的内存资源。

         之前C++标准库中定义的智能指针std::auto_ptr<T>,因其设计存在缺陷,所以已不再推荐使用。C++11引入了新的智能指针:unique_ptr、shared_ptr和weak_ptr。

 

一:unique_ptr

         unique_ptr类似于auto_ptr。两个unique_ptr实例不能管理同一个对象。

        

1:类似于auto_ptr,unique_ptr也具有get成员函数,该函数返回指向被管理对象的指针;如果unique_ptr不拥有任何对象,则get返回nullptr;

 

2:它没有复制构造函数和赋值操作符,而具有移动构造函数和移动赋值操作符;当把源unique_ptr对象移动复制或移动赋值给目标unique_ptr对象后,源unique_ptr对象所掌握的资源的所属权,就转移给目的unique_ptr对象,而源unique_ptr对象就不再掌握资源,所以源unique_ptr对象的unique_ptr::get返回nullptr:

class X
{
    int x;
public:
    X(int x) : x(x) { cout << "ctor invoked: " << x << endl; }
    ~X() { cout << "dtor invoked: " << x << endl; }
    void sayHi() const { cout << "HI: " << x << endl; }
};
 
int main()
{
    unique_ptr<X> a(new X(2));

    //unique_ptr<X> b(a);
    //unique_ptr<X> c;  c = a;

    unique_ptr<X> d = std::move(a);
    cout << a.get() << endl;
    d->sayHi();
    cout << "---------------\n";

    unique_ptr<X> e(new X(3));
    unique_ptr<X> f;
    f = std::move(e);
    cout << e.get() << endl;
    f->sayHi();
    cout << "---------------\n";
}

 

         unique_ptr没有复制构造函数和复制赋值操作符,只有移动构造函数和移动赋值操作符。所以,在复制或者赋值时,需要使用std::move将对象转换为右值。如果去掉了main函数中的注释代码,则会报编译错误: error: use of deleted function…

上面代码的运行结果如下:

ctor invoked: 2
0
HI: 2
---------------
ctor invoked: 3
0
HI: 3
---------------
dtor invoked: 3
dtor invoked: 2

 

         当超出unique_ptr的作用域时,会自动删除它指向的内存对象;

 

         3:unique_ptr的默认行为是掌管指向使用new申请的内存的指针的所属权,并在必要情况下使用delete释放内存。unique_ptr的声明如下:

template <typename T, typename Deleter = std::default_delete<T>>
class unique_ptr;

 

模板类std::default_delete<T>实现了一个函数对象,调用时执行delete操作,类似于下方的实现:

template <typename T>
class default_delete
{
public:
    void operator()(T* obj) const
    {
        delete obj;
    }
};

 

 

可以用自己实现的释放资源函数对象,替换默认的deleter。比如,对于使用malloc申请的资源,如果需要用unique_ptr接管的话,必须使用free释放。例子如下:

struct my_point
{
    int x; 
    int y;
};

struct my_point_deleter
{
    void operator()(my_point* p) const
    {
        cout << "free " << p << endl;
        free(p);
    }
};

void show_point(const my_point& o)
{
    cout << "(" << o.x << ", " << o.y << ")" << endl;
}

int main()
{
    unique_ptr<my_point, my_point_deleter> p(static_cast<my_point*>(malloc(sizeof(my_point))));
    cout << "p is " << p.get() << endl;

    p->x = 5;
    p->y = 8;
    show_point(*p);
}

 

运行结果如下:

p is 0x2443010
(5, 8)
free 0x2443010

 

 

4:reset成员函数,用于更改unique_ptr所管理的对象,而原来所掌管的对象则被销毁。移动赋值操作A=B,A原来所掌管的对象也会被销毁:

int main()
{
    unique_ptr<X> a(new X(2));
    unique_ptr<X> b(new X(3));
    cout << "---------------\n";

    a = move(b);
    cout << "---------------\n";

    a.reset(new X(4));
    cout << "---------------\n";

    a.reset(nullptr);
    cout << "---------------\n";
}

 

结果如下:

ctor invoked: 2
ctor invoked: 3
---------------
dtor invoked: 2
---------------
ctor invoked: 4
dtor invoked: 3
---------------
dtor invoked: 4
---------------

 

 

5:只有非const的unique_ptr能够将其对某对象的所有权转移给其他unique_ptr。也就是说,如果a是个const unique_ptr对象,则下面的语句都是非法的:

    a.reset();
    b = std::move(a);
    unique_ptr<X> c(std::move(a));

 

 

6:unique_ptr实现了”*” 和 “->”操作符的重载。因此,可以像使用传统指针那样,使用unique_ptr;

 

7:unique_ptr实现了operator bool函数。也即是说,可以直接在if()中判断,该unique_ptr是否拥有某个对象:

int main()
{
    std::unique_ptr<int> ptr(new int(42));
 
    if (ptr) 
        std::cout << "before reset, ptr is: " << *ptr << ‘\n‘;
        
    ptr.reset();
    
    if (ptr) 
        std::cout << "after reset, ptr is: " << *ptr << ‘\n‘;
    else
        std::cout << "after reset, ptr is null\n";
}

 

结果如下:

before reset, ptr is: 42
after reset, ptr is null

 

 

8:C++14引入了make_unique,用于更加方便的在堆上创建对象,并将该对象交给unique_ptr对象掌管。所以,下面两种写法是等价的:

unique_ptr<my_point> point(new my_point { 6, 5 });
auto point = make_unique<my_point>(6, 5);

 

使用make_unique隐藏了new的调用(that is good because we do not want to have our programs with new but without delete )

 

9:可以将unique_ptr放到vector中。因为unique_ptr不支持复制,所以在调用push_back时,unique_ptr对象必须是个右值:

int main()
{
    std::vector< std::unique_ptr<X> > vu;

    vu.push_back(std::unique_ptr<X>(new X(2)));

    std::unique_ptr<X> a(new X(3));
    vu.push_back(std::move(a));

    for(auto iter = vu.begin(); iter != vu.end(); iter++)
    {
        (*iter)->sayHi();
    }
}

 

结果如下:

ctor invoked: 2
ctor invoked: 3
HI: 2
HI: 3
dtor invoked: 2
dtor invoked: 3

 

 

10:unique_ptr也支持管理动态申请的数组:

class X
{
    int x;
public:
    X(int x = 1) : x(x) { cout << "ctor invoked: " << x << endl; }
    ~X() { cout << "dtor invoked: " << x << endl; }
    void sayHi() const { cout << "HI: " << x << endl; }
};

int main()
{
    const int size = 3;
    std::unique_ptr<X[]> xs(new X[size]);
    
    for(int i = 0; i < size; i++)
    {
        xs[i].sayHi();
    }
}

 

结果如下:

ctor invoked: 1
ctor invoked: 1
ctor invoked: 1
HI: 1
HI: 1
HI: 1
dtor invoked: 1
dtor invoked: 1
dtor invoked: 1

 

 

二:shared_ptr

shared_ptr使用引用计数,允许多个shared_ptr管理堆中的同一个对象。只有引用计数变为0时,堆中的对象才被销毁。

多个shared_ptr共享同一对象的所有权,只能是通过复制构造函数或者复制赋值操作符实现。构造shared_ptr时,如果使用的底层指针已经被其他shared_ptr所有,这是一种未定义行为。

 

1:shared_ptr具有复制构造函数和移动构造函数,可以使用use_count成员函数返回有多少个shared_ptr拥有同一个对象。对于移动构造函数:A(std::move(B)),之后B不再拥有任何对象。

int main()
{
    std::shared_ptr<X> sx1(new X(2));
    std::cout << "sx1.get is " << sx1.get() << std::endl;
    std::cout << "sx1.use_count is " << sx1.use_count() << std::endl;
    std::cout << "---------------------\n";

    std::shared_ptr<X> sx2(sx1);
    std::cout << "sx2.get is " << sx2.get() << std::endl;
    std::cout << "sx2.use_count is " << sx2.use_count() << std::endl;
    std::cout << "---------------------\n";

    std::shared_ptr<X> sx3(std::move(sx1));
    std::cout << "sx1.get is " << sx1.get() << std::endl;
    std::cout << "sx1.use_count is " << sx1.use_count() << std::endl;
    std::cout << "sx3.get is " << sx3.get() << std::endl;
    std::cout << "sx3.use_count is " << sx3.use_count() << std::endl;
    std::cout << "---------------------\n";
}

 

运行结果如下:

ctor invoked: 2
sx1.get is 0x12f5010
sx1.use_count is 1
---------------------
sx2.get is 0x12f5010
sx2.use_count is 2
---------------------
sx1.get is 0
sx1.use_count is 0
sx3.get is 0x12f5010
sx3.use_count is 2
---------------------
dtor invoked: 2

 

 

2:类似于unique_ptr,shared_ptr也支持自定义deleter。

struct my_point_deleter
{
    void operator()(my_point* p) const
    {
        cout << "free " << p << endl;
        free(p);
    }
};

int main()
{
    std::shared_ptr<my_point> pm(static_cast<my_point*>(malloc(sizeof(my_point))), 
            my_point_deleter());

    std::cout << "pm.get is " << pm.get() << std::endl;     
    pm->x = 1;
    pm->y = 2;

    show_point(*pm);
    std::cout << "-----------------\n";
}

 

这里构造shared_ptr对象pm时,第二个参数是my_point_deleter类对象,当需要释放shared_ptr所拥有的对象时,就会自动调用该对象的operator()函数。

结果如下:

pm.get is 0xd30010
(1, 2)
-----------------
free 0xd30010

 

 

3:reset成员函数,用于更改shared_ptr所管理的对象,而原来所掌管的对象,其引用计数减1:

如果reset参数为空,则表示shared_ptr释放对源对象的拥有权;

注意,ptr不能是已经被其他shared_ptr所管理的对象,否则是未定义的;

int main()
{
    std::shared_ptr<X> pm1;
    std::cout << "pm1.get is " << pm1.get() << std::endl;
    std::cout << "pm1.use_count is " << pm1.use_count() << std::endl;
    std::cout << "-----------------\n";

    pm1.reset(new X);
    std::cout << "pm1.get is " << pm1.get() << std::endl;
    std::cout << "pm1.use_count is " << pm1.use_count() << std::endl;
    pm1->sayHi();
    std::cout << "-----------------\n";

    pm1.reset(new X(2));
    std::cout << "pm1.get is " << pm1.get() << std::endl;
    std::cout << "pm1.use_count is " << pm1.use_count() << std::endl;
    pm1->sayHi();
    std::cout << "-----------------\n";

    pm1.reset();
    std::cout << "pm1.get is " << pm1.get() << std::endl;
    std::cout << "pm1.use_count is " << pm1.use_count() << std::endl;
    std::cout << "-----------------\n";
    return 0;
}

 

结果如下:

pm1.get is 0
pm1.use_count is 0
-----------------
ctor invoked: 1
pm1.get is 0xebb010
pm1.use_count is 1
HI: 1
-----------------
ctor invoked: 2
dtor invoked: 1
pm1.get is 0xebb050
pm1.use_count is 1
HI: 2
-----------------
dtor invoked: 2
pm1.get is 0
pm1.use_count is 0
-----------------

 

 

4:复制赋值操作A=B,A原来所掌管的对象的引用计数减1,而B所掌管的对象的引用计数加1,而移动赋值操作符A=B,赋值之后,B不再掌握任何对象:

int main()
{
    std::shared_ptr<X> pm1(new X(2));
    std::shared_ptr<X> pm2(new X(3));
    pm2 = pm1;
    std::cout << "pm1.get is " << pm1.get() << std::endl;
    std::cout << "pm2.get is " << pm2.get() << std::endl;
    std::cout << "pm1.use_count is " << pm1.use_count() << std::endl;
    pm2->sayHi();
    std::cout << "-----------------\n";
    
    std::shared_ptr<X> pm3;
    pm3 = std::move(pm1);
    std::cout << "pm1.get is " << pm1.get() << std::endl;
    std::cout << "pm2.get is " << pm2.get() << std::endl;
    std::cout << "pm3.get is " << pm3.get() << std::endl;
    std::cout << "pm2.use_count is " << pm2.use_count() << std::endl;
    pm3->sayHi();
    std::cout << "-----------------\n";
}

 

结果如下:

ctor invoked: 2
ctor invoked: 3
dtor invoked: 3
pm1.get is 0x968010
pm2.get is 0x968010
pm1.use_count is 2
HI: 2
-----------------
pm1.get is 0
pm2.get is 0x968010
pm3.get is 0x968010
pm2.use_count is 2
HI: 2
-----------------
dtor invoked: 2

 

 

5:可以将shared_ptr放到容器中。

int main()
{
    std::shared_ptr<X> sx1(new X(2));
    std::vector< std::shared_ptr<X> > vs;

    vs.push_back(sx1);
    std::cout << "sx1.get is " << sx1.get() << std::endl;
    std::cout << "vs[0].get is " << vs[0].get() << std::endl;
    std::cout << "sx1.use_count is " << sx1.use_count() << std::endl;
    vs[0]->sayHi();
    std::cout << "---------------------\n";

    std::shared_ptr<X> sx2(new X(3));
    std::cout << "sx2.get is " << sx2.get() << std::endl;

    vs.push_back(std::move(sx2));
    std::cout << "sx2.get is " << sx2.get() << std::endl;
    std::cout << "vs[1].get is " << vs[1].get() << std::endl;
    std::cout << "vs[1].use_count is " << vs[1].use_count() << std::endl;
    vs[1]->sayHi();
    std::cout << "---------------------\n";
}

 

结果如下:

ctor invoked: 2
sx1.get is 0x1abf010
vs[0].get is 0x1abf010
sx1.use_count is 2
HI: 2
---------------------
ctor invoked: 3
sx2.get is 0x1abf070
sx2.get is 0
vs[1].get is 0x1abf070
vs[1].use_count is 1
HI: 3
---------------------
dtor invoked: 3
dtor invoked: 2

 

 

6:shared_ptr实现了operator bool函数。也即是说,可以直接在if()中判断该shared_ptr是否拥有某个对象:

int main()
{
    std::unique_ptr<int> ptr(new int(42));
 
    if (ptr) 
        std::cout << "before reset, ptr is: " << *ptr << ‘\n‘;
        
    ptr.reset();
    
    if (ptr) 
        std::cout << "after reset, ptr is: " << *ptr << ‘\n‘;
    else
        std::cout << "after reset, ptr is null\n";
}

 

结果如下:

before reset, ptr is: 42
after reset, ptr is null

 

 

7:推荐使用make_shared创建shared_ptr,而不是使用shared_ptr的构造函数。

一般情况下,shared_ptr内部会持有两个指针,一个是指向被管理对象的指针;另一个是指向控制块的指针。所谓控制块,就是记录引用计数等属性的数据结构。

当使用make_shared创建shared_ptr时,被管理对象以及控制块的内存是一起申请的;而用构造函数创建的shared_ptr,被管理对象和控制块的内存是分开申请的。所以,make_shared的效率更高一些。

 

make_shared主要做三件事:

申请被管理对象以及引用计数的内存;调用适当的构造函数初始化对象;返回一个shared_ptr。

例子如下:

int main()
{
    std::shared_ptr<int> ptrint = std::make_shared<int>(2);
    std::shared_ptr<X> ptrX = std::make_shared<X>(3);

    cout << "*ptrint is " << *ptrint << endl;
    ptrX->sayHi();
}

 

结果如下:

ctor invoked: 3
*ptrint is 2
HI: 3
dtor invoked: 3

 

 

三:weak_ptr

shared_ptr的缺点在于不适用与循环引用的情况,这也是引入std::weak_ptr的原因。所谓循环引用,例子如下:

struct Child;
 
struct Parent
{
    shared_ptr<Child> child;
     
    ~Parent() { cout << "Bye Parent" << endl; }
     
    void hi() const { cout << "Hello" << endl; }
};
 
struct Child
{
    shared_ptr<Parent> parent;
     
    ~Child() { cout << "Bye Child" << endl; }
};
 
int main()
{
    auto parent = make_shared<Parent>();
    auto child = make_shared<Child>();
    parent->child = child;
    child->parent = parent;
    child->parent->hi();
}

 

上面代码的运行结果,只打印出”Hello”,而并没有打印出"Bye Parent"或"Bye Child",说明Parent和Child的析构函数并没有调用到。这是因为Parent和Child对象内部,具有各自指向对方的shared_ptr,加上parent和child这两个shared_ptr,说明每个对象的引用计数都是2。当程序退出时,即使parent和child被销毁,也仅仅是导致引用计数变为了1,因此并未销毁Parent和Child对象。

这种情况下,就可以使用weak_ptr来解决这种问题:

struct Child;
 
struct Parent
{
    shared_ptr<Child> child;
     
    ~Parent() { cout << "Bye Parent" << endl; }
     
    void hi() const { cout << "Hello" << endl; }
};
 
struct Child
{
    weak_ptr<Parent> parent;
     
    ~Child() { cout << "Bye Child" << endl; }
};
 
int main()
{
    auto parent = make_shared<Parent>();
    auto child = make_shared<Child>();
    parent->child = child;
    child->parent = parent;
    child->parent.lock()->hi();
}

 

上面的代码可以得到正确的结果:

Hello
Bye Parent
Bye Child

 

 

1:weak_ptr是对shared_ptr的封装,但是它不拥有被指向的对象,因而也就不会导致引用计数的变化。

可以使用shared_ptr对象构造weak_ptr,或对其进行赋值。表示该weak_ptr“共享”shared_ptr所拥有的对象。如果shared_ptr为空(不拥有任何对象),则该weak_ptr也是空的。

 

2:weak_ptr::use_count函数,返回当前有多少个shared_ptr实例共享被管理对象。

weak_ptr::expired函数检查被管理对象是否已经被销毁了,如果已经被销毁,则该函数返回true,否则返回false。expired函数要比use_count更快一些。例子如下:

struct Foo {};
 
int main()
{
   std::weak_ptr<Foo> w_ptr;
  {
      auto ptr = std::make_shared<Foo>();
      w_ptr = ptr;
      std::cout << "w_ptr.use_count() inside scope: " << w_ptr.use_count() << ‘\n‘;
   }
   std::cout << "w_ptr.use_count() out of scope: " << w_ptr.use_count() << ‘\n‘;
   std::cout << "w_ptr.expired() out of scope: " << std::boolalpha << w_ptr.expired() << ‘\n‘;
}

 

结果如下:

w_ptr.use_count() inside scope: 1
w_ptr.use_count() out of scope: 0
w_ptr.expired() out of scope: true

 

 

3:weak_ptr所拥有的,是对shared_ptr所管理对象的弱引用,它必须临时转换为shared_ptr之后,才能临时性的访问引用对象。weak_ptr没有实现->操作符,相反,它实现了lock函数,该函数创建临时的shared_ptr,从而增加了它指向对象的引用计数,避免该对象被释放。

如果weak_ptr没有引用任何对象,则lock返回的shared_ptr对象也不引用任何对象,否则,lock返回的shared_ptr增加所引用对象的引用计数。

void observe(std::weak_ptr<int> weak) 
{
    if (auto observe = weak.lock()) {
        std::cout << "\tobserve() able to lock weak_ptr<>, value=" << *observe << "\n";
    } else {
        std::cout << "\tobserve() unable to lock weak_ptr<>\n";
    }
}
 
int main()
{
    std::weak_ptr<int> weak;
    std::cout << "weak_ptr<> not yet initialized\n";
    observe(weak);
 
    {
        auto shared = std::make_shared<int>(42);
        weak = shared;
        std::cout << "weak_ptr<> initialized with shared_ptr.\n";
        observe(weak);
    }
 
    std::cout << "shared_ptr<> has been destructed due to scope exit.\n";
    observe(weak);
}

 

上面的代码中,首先构造一个空的weak_ptr对象weak,因此在observe函数中,weak_ptr::lock返回的shared_ptr也是空的;接下来在嵌套作用域中,首先构造了一个指向int类型的shared_ptr,然后用该shared_ptr对weak_ptr进行赋值,这样在observe函数中,weak_ptr::lock返回的shared_ptr也就临时拥有了该int类型对象;嵌套作用域结束后,其中的shared_ptr就被销毁了,weak又再次为空,所以observe函数中,weak_ptr::lock返回的shared_ptr又是空的了。结果如下:

weak_ptr<> not yet initialized
        observe() unable to lock weak_ptr<>
weak_ptr<> initialized with shared_ptr.
        observe() able to lock weak_ptr<>, value=42
shared_ptr<> has been destructed due to scope exit.
        observe() unable to lock weak_ptr<>

 

 

四:shared_ptr中的控制结构

In a typical implementation, std::shared_ptr holds only two pointers:

the stored pointer (one returned by get());

a pointer to control block.

 

The control block is a dynamically-allocated object that holds:

either a pointer to the managed object or the managed object itself;

the deleter (type-erased);

the allocator (type-erased);

the number of shared_ptrs that own the managed object;

the number of weak_ptrs that refer to the managed object.

 

         shared_ptr中包含两个指针,一个指向被管理的对象(也就是get()的返回值),另一个指向控制块。

         控制块中包含:指向被管理对象的指针;deleter和allocator;引用计数。比如,shared_ptr<Foo> 的数据结构如下图所示,其中 deleter 和 allocator 是可选的:

 技术分享

 

The pointer held by the shared_ptr directly is the one returned by get(), while the pointer/object held by the control block is the one that will be deleted when the number of shared owners reaches zero. These pointers are not necessarily equal.

shared_ptr持有的指向被管理对象的指针,就是get()的返回值;而控制块中持有的指针,是当引用计数为0时,会被delete的指针,这两个指针的类型不一定相同,只要它们之间存在隐式转换。

 

这是 shared_ptr 的一大功能。分 3 点来说:

1: 无需虚析构

假设base 是 derived 的基类,但是 base 和 derived 都没有虚析构。

 

shared_ptr<derived > sp1(new derived );     // 控制块中指针的类型是 derived *

shared_ptr<base > sp2 = sp1;                         // 可以赋值,自动向上转型(up-cast)

sp1.reset();                                                         // 这时 derived 对象的引用计数降为 1

此后 sp2 仍然能安全地管理 derived 对象的生命期,并安全完整地释放 derived ,因为其控制块记住了 derived 的实际类型。具体代码如下:

class base
{
public:
    base() {cout << "base ctor" << endl;}
    ~base() {cout << "base dtor" << endl;}
};

class derived:public base
{
public:
    derived() {cout << "derived ctor" << endl;}
    ~derived() {cout << "derived dtor" << endl;}
};

int main()
{
    derived *pd = new derived;
    base *pb = pd;
    delete pb;

    cout << "---------------\n";

    shared_ptr<derived> spd(new derived);
    shared_ptr<base> spb = spd;
    spd.reset();
}

 

         对于原始指针而言,将指向derived的指针pd赋值给指向base的指针pb,在delete pb时,只会调用base的析构函数,而不会调用derived的析构函数。

         而对于shared_ptr而言,使用指向derived的shared_ptr<derived> spd,初始化指向base的shared_ptr<base> spb,当超出作用域时,spb可以完整的释放 derived ,因为其控制块记住了 derived 的实际类型。

         代码结果如下:

base ctor
derived ctor
base dtor
---------------
base ctor
derived ctor
derived dtor
base dtor

 

 

         2:shared_ptr<void> 可以指向并安全地管理(析构或防止析构)任何对象;

shared_ptr<derived> sp1(new derived);       // 控制块中指针的类型是 derived*

shared_ptr<void> sp2 = sp1;                                   // 可以赋值,derived* 向 void* 自动转型

sp1.reset();                                                         // 这时 derived对象的引用计数降为 1

此后 sp2 仍然能安全地管理 derived对象的生命期,并安全完整地释放 derived,不会出现 delete void* 的情况,因为 delete 的是控制块中的指针,不是 sp2.get()的返回值。

具体代码如下:

derived *pd = new derived;
void *pv = pd;
delete pv;

cout << "---------------\n";

shared_ptr<derived> spd(new derived);
shared_ptr<void> spv = spd;
spd.reset();

 

对于原始指针而言,将指向derived的指针pd赋值给void类型的指针pv,在delete pv时,GCC会报编译警告,并且,实际运行时没有任何作用;

warning: deleting ‘void*’ is undefined [enabled by default]

 

         而对于shared_ptr而言,使用指向derived的shared_ptr<derived> spd,初始化指向void的shared_ptr<void> spv,当超出作用域时,spv可以完整的释放 derived ,因为其控制块记住了 derived 的实际类型。

         代码结果如下:

base ctor
derived ctor
---------------
base ctor
derived ctor
derived dtor
base dtor

 

 

3. 多继承。

假设 base1 是 derived的多个基类之一,那么:

shared_ptr<derived> sp1(new derived);

shared_ptr<base1 > sp2 = sp1;  //这时 sp1.ptr 和 sp2.ptr 可能指向不同的地址,因为

//base1 subobject 在 derived object 中的 offset 可能不为0。

sp1.reset();                  // 此时 derived对象的引用计数降为 1

 

但是 sp2 仍然能安全地管理 derived对象的生命期,并安全完整地释放 derived,因为 delete 的不是 base1 *,而是原来的 derived*。换句话说,sp2中和控制块中的指针可能具有不同的值(当然它们的类型也不同)。

 

陈硕 http://blog.csdn.net/solstice/article/details/8547547

 

参考:

http://en.cppreference.com/w/cpp/memory

https://oopscenities.net/2013/04/09/smart-pointers-part-2-unique_ptr-2/

智能指针简介

标签:引用   erase   false   direct   smart   use   error   cat   operator   

原文地址:http://www.cnblogs.com/gqtcgq/p/7492173.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!