智能指针简介

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

之前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/

时间: 2024-10-16 12:41:14

智能指针简介的相关文章

(转)Delphi2009初体验 - 语言篇 - 智能指针(Smart Pointer)的实现

快速导航 一. 回顾历史二. 智能指针简介三. Delphi中的interface四. Delphi中智能指针的实现五. interface + 泛型 = 强类型的智能指针!六. 智能指针与集合七. 注意事项八. 总结 本随笔所有源代码打包下载 一.回顾历史 在c++中,对象可以创建在栈里,也可以创建在堆里.如: class CTestClass{public: CTestClass() { printf("Create"); } void DoPrint() {} ~CTestCla

【c++工程实践】智能指针

一.智能指针简介 a smart pointer is an abstract data type that simulates a pointer while providing added features, such as automatic memory management or bounds checking. 智能指针和普通指针的区别在于智能指针实际上是对普通指针加了一层封装机制,这样的一层封装机制的目的是为了使得智能指针可以方便的管理一个对象的生命期. 在C++中,我们知道,如果

智能指针(三):unique_ptr使用简介

我们知道auto_ptr通过复制构造或者通过=赋值后,原来的auto_ptr对象就报废了.所有权转移到新的对象中去了.而通过shared_ptr可以让多个智能指针对象同时拥有某一块内存的访问权.但假如我们不希望多个内存块被多个智能指针对象共享,同时又不会像auto_ptr那样不知不觉的就让原来的auto_ptr对象失效,可咋整呢? 这个时候就要使用unique_ptr了,顾名思义嘛,unique是唯一的意思.说明它跟auto_ptr有点类似,就是同时只能有一个智能指针对象指向某块内存.但它还有些

基于C/S架构的3D对战网络游戏C++框架 _05搭建系统开发环境与Boost智能指针、内存池初步了解

本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): 1.实现基本通信框架,包括对游戏的需求分析.设计及开发环境和通信框架的搭建: 2.实现网络底层操作,包括创建线程池.序列化网络包等: 3.实战演练,实现类似于CS反恐精英的3D对战网络游戏: 技术要点:C++面向对象思想.网络编程.Qt界面开发.Qt控件知识.Boost智能指针.STL算法.STL.

C++ 智能指针

本文转自: http://blog.csdn.net/xt_xiaotian/article/details/5714477 (纯属自学转载) 一.简介 由于 C++ 语言没有自动内存回收机制,程序员每次 new 出来的内存都要手动 delete.程序员忘记 delete,流程太复杂,最终导致没有 delete,异常导致程序过早退出,没有执行 delete 的情况并不罕见. 用智能指针便可以有效缓解这类问题,本文主要讲解参见的智能指针的用法.包括:std::auto_ptr.boost::sco

Boost智能指针-基础篇

简介 内存管理一直是 C++ 一个比较繁琐的问题,而智能指针却可以很好的解决这个问题,在初始化时就已经预定了删除,排解了后顾之忧.1998年修订的第一版C++标准只提供了一种智能指针:std::auto_ptr(现以废弃),它基本上就像是个普通的指针:通过地址来访问一个动态分配的对象.std::auto_ptr之所以被看作是智能指针,是因为它会在析构的时候调用delete操作符来自动释放所包含的对象.当然这要求在初始化的时候,传给它一个由new操作符返回的对象的地址.既然std::auto_pt

[C/C++] 智能指针学习

一.简介 由于 C++ 语言没有自动内存回收机制,程序员每次 new 出来的内存都要手动 delete.程序员忘记 delete,流程太复杂,最终导致没有 delete,异常导致程序过早退出,没有执行 delete 的情况并不罕见. 用智能指针便可以有效缓解这类问题,本文主要讲解参见的智能指针的用法.包括:std::auto_ptr.boost::scoped_ptr.boost::shared_ptr.boost::scoped_array.boost::shared_array.boost:

【转】C++ 智能指针详解

一.简介 由于 C++ 语言没有自动内存回收机制,程序员每次 new 出来的内存都要手动 delete.程序员忘记 delete,流程太复杂,最终导致没有 delete,异常导致程序过早退出,没有执行 delete 的情况并不罕见.用智能指针便可以有效缓解这类问题,本文主要讲解参见的智能指针的用法.包括:std::auto_ptr.boost::scoped_ptr.boost::shared_ptr.boost::scoped_array.boost::shared_array.boost::

[转]C++ 智能指针详解

C++ 智能指针详解   一.简介 由于 C++ 语言没有自动内存回收机制,程序员每次 new 出来的内存都要手动 delete.程序员忘记 delete,流程太复杂,最终导致没有 delete,异常导致程序过早退出,没有执行 delete 的情况并不罕见. 用智能指针便可以有效缓解这类问题,本文主要讲解参见的智能指针的用法.包括:std::auto_ptr.boost::scoped_ptr.boost::shared_ptr.boost::scoped_array.boost::shared