C++11新特性之智能指针

  1、shared_ptr:一种计数指针,被指向的对象在引用计数为0时删除。它表示共享的所有权(负责对象的删除销毁)。需要包含<memory>,下同。

// 定义删除器
struct Deleter
{
public:
    void operator() (Base *p)
    {
        cout << "[deleter called]" << endl;
        delete p;
    }
};

int main()
{
    shared_ptr<Base> p1(new Base, Deleter());
    {
        shared_ptr<Base> p2(p1);    // 这里p1/p2的use_count()为2
        {
            shared_ptr<Base> p3(p2);    // 这里p1/p2/p3的use_count()为3
        }    // p1/p2的use_count()变为2
    }    // p1的use_count()变为1

    p1.reset();    // 无参的reset()将使p1变为空(就像默认构造时一样)

    // p1的use_count()变为0且上面的new Base被删除/析构

    return 0;
}

  以下用法是错误的:

// 错误1:既使用shared_ptr,又自己管理原生指针。原生指针被重复析构
int *p = new int(9);
shared_ptr<int> sp1(p);
delete p;

// 错误2:多个shared_ptr均从同一个原生指针构造。原生指针被重复析构
// 多个shared_ptr管理同一个原生指针,则后续的shared_ptr都应直接或间接(通过weak_ptr)从第一个构造
int *q = new int(10);
shared_ptr<int> sp2(q);
shared_ptr<int> sp3(q);

  有时候,需要在类的成员函数里面获取到“指向”当前对象的shared_ptr(然后把它传递给其他函数)。此时,只需要继承enable_shared_from_this,即可在成员函数中使用shared_from_this()获取到shared_ptr。示例:

class Foo;

class Bar
{
public:
    void test(shared_ptr<Foo> sp);
};

class Foo : public enable_shared_from_this<Foo>
{
public:
    void test();
    void print();
};

void Bar::test(shared_ptr<Foo> sp)
{
    // 此时sp.use_count()为3
    sp -> print();
}

void Foo::test()
{
    // 若换成shared_ptr<Foo> sp = shared_ptr<Foo>(this);会出错
    // 这相当于使用一个原生指针分别构造两个shared_ptr,会造成重复释放的问题
    shared_ptr<Foo> sp = shared_from_this();  // 此时sp.use_count()为2
    Bar bar;
    bar.test(sp);
    // 此时sp.use_count()为2
}

void Foo::print() { cout << "in Foo::print" << endl; }

int main()
{
    shared_ptr<Foo> sp1(new Foo);
    sp1 -> test();
    // 此时sp1.use_count()为1

    // !!!错误用法,抛出bad_weak_ptr异常!!!
    // 原因(参考boost的enable_shared_from_this.hpp):enable_shared_from_this有一个weak_ptr类型的成员,
    // 它只能由shared_ptr通过enable_shared_from_this的一个成员函数赋值(故使用以下方式时,该成员为空),
    // shared_from_this()正是通过该成员“获取”到shared_ptr
    Foo *fp = new Foo;
    fp -> test();
    delete fp;
}

  2、weak_ptr:Weak shared pointer

int main()
{
    shared_ptr<int> sp1(new int(10));

    // 可以用shared_ptr/weak_ptr构造weak_ptr
    // weak_ptr拥有资源的访问权,但没有所有权(不会增加引用计数)
    weak_ptr<int> wp(sp1);  // wp和sp1的use_count()均为1

    if (!wp.expired())
    {
        // lock():从weak_ptr“获取”一个可用的shared_ptr对象
        shared_ptr<int> sp2 = wp.lock();  // wp和sp1的use_count()均为2
        *sp2 = 100;
    }

    // 此时wp和sp1的use_count()均为1

    return 0;
}

  expired():检查weak_ptr对象是否失效(为空或已经没有shared_ptr和它一起观测某个资源)。和空weak_ptr一样,失效的weak_ptr不能用于还原出shared_ptr(lock())。expired()和use_count()==0返回相同的结果,但效率更高。示例:

weak_ptr<int> wp;    // 此时wp.expired()为1

shared_ptr<int> sp1(new int);
wp = sp1;
shared_ptr<int> sp2 = wp.lock();

// 此时wp.expired()为0

sp2.reset();    // 此时wp.expired()为0
sp1.reset();    // 此时wp.expired()为1

  另外,weak_ptr没有重载*和->运算符,不能像普通指针一样使用(要借助lock(),参考第一个例子中的sp2)。

  shared_ptr还有“环状引用”的问题,也需要使用weak_ptr来规避,如下例:

class parent;
class children;
typedef shared_ptr<parent> parent_ptr;  // 改为typedef weak_ptr<parent> parent_ptr;方可避免“环状引用”的问题
typedef shared_ptr<children> children_ptr;  // 改为typedef weak_ptr<children> children_ptr;方可避免“环状引用”的问题

class parent
{
public:
    children_ptr children;
};

class children
{
public:
    parent_ptr parent;
};

int main()
{
    shared_ptr<parent> father(new parent);
    shared_ptr<children> son(new children);
    father -> children = son;
    son -> parent = father;  // father和son的use_count()均为2,程序退出时没有调用parent和children的析构函数!!!

    return 0;
}

  3、unique_ptr:

  1)在了解unique_ptr之前,先来回顾一下auto_ptr。

  auto_ptr:Automatic Pointer(自C++11起已弃用)。

  auto_ptr对象对它管理的指针拥有所有权,即负责其内存释放(释放时机:auto_ptr对象销毁时)。

  和shared_ptr一样,用同一个原生指针初始化多个auto_ptr对象会导致重复释放内存的错误。

class Base
{
public:
    Base() {cout << "in Base" << endl;}
    ~Base() {cout << "in ~Base" << endl;}
    void test() {cout << "in test" << endl;}
};

int main()
{
    auto_ptr<int> ap1(new int);
    // 基本操作
    *ap1 = 10;
    int *p = ap1.get();  // *p == 10
    auto_ptr<Base> ap2(new Base);
    ap2 -> test();

    auto_ptr<Base> ap3 = ap2; // 赋值或“复制”构造时会转移所有权(故不能用于STL容器中):ap2.get()变成NULL
    ap3 -> test();

    auto_ptr<Base> ap4(new Base);
    Base *bp = ap4.release();  // ap4.get()变成NULL。释放所有权,不再对之前管理的指针(的内存)负责。返回之前管理的指针
    delete bp;

    auto_ptr<Base> ap5(new Base);
    ap5.reset(); // “显式”销毁/析构其指向的对象。可设置指向新的对象

    return 0;
}

  参考资料:

  http://www.cplusplus.com

不断学习中。。。

时间: 2024-12-20 04:49:14

C++11新特性之智能指针的相关文章

Cocos2d-x 3.1.1 学习日志6--30分钟了解C++11新特性

新的关键字 auto C++11中引入auto第一种作用是为了自动类型推导 auto的自动类型推导,用于从初始化表达式中推断出变量的数据类型.通过auto的自动类型推导,可以大大简化我们的编程工作.auto实际上实在编译时对变量进行了类型推导,所以不会对程序的运行效率造成不良影响.另外,似乎auto并不会影响编译速度,因为编译时本来也要右侧推导然后判断与左侧是否匹配.如果没有auto关键字 写个迭代器要写很长长,这也算是节省了我们的脑细胞吧,~~~~(>_<)~~~~ !! auto a; /

9秒学院学C++11新特性

9秒学院C++11新特性学习笔记 分类: C/C++ 最近学习了C++11的新特性,将学习内容整理下来以巩固记忆,C++11的新特性,可以分为两部分,第一部分是C++11核心语言的特性,第二部分是STL标准库的新特性.学习C++11主要参考了wiki上的一篇文章,在介绍右值引用的时候还参考了MSDN上一篇文章,由于这两篇文章写的时间比较早,和实际有些出入,我的开发环境是win8,vs2012,很多C++11特性还没支持,所以只整理了vs2012已经支持了的特性. 第一部分:核心语言的特性 一.

C++11——新特性总结

前言: 开学过去一个半月了,说来十分惭愧,由于和女友最后还是分开了,导致这段时间一直在沉沦,每天晚上回去打打lol或者cs,就睡觉,基本上把我自己定下的自学目标给抛弃了.好在这段时间里还是凭借以前的基础投了不少岗位,也笔试了不少公司,基本都通过了笔试.第一次面试是网易,结果在最后一轮的技术面上挂了下来.其实回想起来,当时问的问题我其实之前都有仔细的专研过,只不过时间太久忘了罢了.这也要怪我自己准备不够充分.之前腾讯的笔试,我其实感觉自己是做砸了的,不过没想到还是得到了面试机会,就在两天之后的下午

[转]30分钟了解C++11新特性

新的关键字 autoC++11中引入auto第一种作用是为了自动类型推导auto的自动类型推导,用于从初始化表达式中推断出变量的数据类型.通过auto的自动类型推导,可以大大简化我们的编程工作.auto实际上实在编译时对变量进行了类型推导,所以不会对程序的运行效率造成不良影响.另外,似乎auto并不会影响编译速度,因为编译时本来也要右侧推导然后判断与左侧是否匹配.如果没有auto关键字 写个迭代器要写很长长,这也算是节省了我们的脑细胞吧,~~~~(>_<)~~~~ !! [html] view

逐个使用C++11新特性

C++11 auto & decltype auto:根据变量初始值来推导变量类型,并用右值初始化变量. decltype:从表达式推导出类型,并将变量定义为该类型,但不用表达式的值初始化该变量. 这里要注意下:decltype(i)--是i的类型,而decltype((i))就是引用了.就像上面例子中的x 就是int &x; 右值引用 新标准在拷贝构造函数.拷贝赋值运算符和析构函数之外,还增加了移动构造函数和移动赋值运算符,而这二位就需要右值引用的支持. 1. 延长将亡值的生命. 1 /

[C++11新特性]第二篇

0.可变数量参数,可变函数模版,变长模版类 c++98可变数量参数 #include<cstdio> #include<cstdarg> double SumOfFloat(int count, ...) { va_list ap; double sum=0; va_start(ap,count); for(int i=0;i<count;i++) sum+=va_arg(ap,double); va_end(ap); return sum; } int main() { p

[cocos2d-x] 一些C++ 11新特性的引入

1.auto关键字的使用 auto关键字原理     在定义变量的时候必须申明类型,c++是强语言类型,在编译阶段需要知道类型,这样的好处是程序效率更高,而动态语言不需要类型申明的需要自推导变量类型.使用了auto是不是c++效率会变慢?完全不是,因为在编译阶段编译器已经帮程序员推导好了变量的类型.前提条件是编译器可以根据当前的程序的状态推导出变量类型.只是编译器更加智能,可能会增加编译工作,但是不会影响运行效率. 实例1:申明普通变量 auto num = 10; 实例2: vector<st

C++11新特性:Lambda函数(匿名函数)

声明:本文参考了Alex Allain的文章http://www.cprogramming.com/c++11/c++11-lambda-closures.html 加入了自己的理解,不是简单的翻译 C++11终于知道要在语言中加入匿名函数了.匿名函数在很多时候可以为编码提供便利,这在下文会提到.很多语言中的匿名函数,如C++,都是用Lambda表达式实现的.Lambda表达式又称为lambda函数.我在下文中称之为Lambda函数. 为了明白Lambda函数的用处,请务必先搞明白C++中的自动

C++11新特性:右值引用和转移构造函数

问题背景 [cpp] view plaincopy #include <iostream> using namespace std; vector<int> doubleValues (const vector<int>& v) { vector<int> new_values( v.size() ); for (auto itr = new_values.begin(), end_itr = new_values.end(); itr != end