C++11读书笔记—6(新指针)

来源:互联网 发布:url传递json对象 编辑:程序博客网 时间:2024/06/05 18:20

问:你为什么不用C/C++?

答:面对一个24小时不能中断运行的程序,程序员的一点内存错误通过积累可能带来灾难性后果。

〇、C++11版本之前的内存

之前我在C/C++基础的专区上已经说了C/C++几个大坑。

(1)野指针问题(2)重复内存释放问题(3)内存泄漏问题

在C++98中就已经有了智能指针这一说法。通过一个模板类型“auto_ptr"来实现。auto_ptr以对象的方式管理堆分配的内存,并在适当的时间析构,释放所获得的堆内存。我们这么写就可以了。

auto_ptr(new int);

auto_ptr的缺点很明显,拷贝时返回一个左值,不能调用delete[],破坏复制性等等,以至于很多C++教材直接去掉这么个神器。C++11在搞新智能指针时,直接废弃了。C++11提供3个智能指针。std::shared_ptr , std::unique_ptr , std::weak_ptr 使用前要#include <memory>

一、C++11的智能指针(本质是个模板类)

1.unique_ptr独占指针

先上代码:

unique_ptr<int> up1(new int(11));cout << *up1 << endl; //11unique_ptr<int> up3 = move(up1);cout << *up3 << endl; //11cout << *up1 << endl;    //这一步会出问题,运行时错误
up1.reset(); up3.reset();//显示释放内存,不会导致运行时错误

unique_ptr,形如其名,独占指针。如果这么写unique_ptr<int> up2 = up1;   就错了,所有权仅能用move转移,转移之后原始指针就失效了。

2.shared_ptr共享指针

shared_ptr共享指针,使用引用计数,每一个shared_ptr的拷贝都指向相同的内存。在最后一个shared_ptr析构时,内存释放。

注意:

(1)不要用一个原始指针初始化多个shared_ptr:

int* ptr= new int;shared_ptr <int>p1(ptr);shared_ptr <int>p2(ptr);//logic error
因为是计数方式,这么写可能会计数错误,提前析构。

(2)不要在函数实参中创建shared_ptr,如下代码:

fuction(shared_ptr <int>p1(new int),g());

有些编译器,可能是从左向右,先执行new int。如果g()发生异常,内存又泄露了。建议分开写。

(3)不要传入this指针到shared_ptr里面

(4)避免循环引用

这是智能指针的我一个最大坑(《深入应用C++》这本书说的,我只能说这很喜闻乐见

struct A{shared_ptr<B> bptr;};struct B{shared_ptr<A> aptr;};int main(){    {//这里有一个作用        ap(new A);bp(new B);ap->bptr = bp;bp->aptr = ap;    }return 0;}


其实我认为这种循环指向的问题,不管是谁都头疼。出了作用域引用计数变为1,并不会减为0。解决方法就是改为weak_ptr。

3.weak_ptr弱引用智能指针

weak_ptr是用来监视shared_ptr的。不会使引用计数加一。不管理shared_ptr内部的指针 ,主要是为了监视shared_ptr的生命周期。weak_ptr没有重载*与->,因为他不共享指针,不能操作资源。(按照定义好像不能算智能指针了)上面的程序改一下就行了。

struct A{shared_ptr<B> bptr;};struct B{weak_ptr<A> aptr;};


二、指针空值nullptr

1.指针空值的衍变

指针空值的设计就是一块不能访问的地址,例如系统保留地址 。开始,人们将其设置为0,因为内存地址为0的地方一般是系统内核保留区,绝对不能访问。NULL其实是个宏定义,就是字面量0。(像java语言中的null的写法是不识别的)
#include<iostream>using namespace std;void f(char* a){cout << "char" << endl;}void f(int a){cout << "int" << endl;}int main(){f(NULL);//注意这个return 0;}

我的原意是NULL属于空值指针(看来还是右值),应该执行上面重载函数;而书上说NULL会做转换变为0直接执行下面的void f(int a)的重载函;但是G++等编译器遇到NULL就直接报二义性错误,VS直接输出“char”
。这种程序员,编译器,C++标准委员会三方不统一的情况很热闹。于是C++11创造出空值引用nullptr。

2.nullptr规则

(1)C++改进了C语言的隐式类型转换。这样C语言的语句不可以了。C++11标准创建一个编译期间关键字nullptr来做隐式转换。

    int *p = (void*)0;//C++会犯错
    int *p = nullptr;//C++11可以

(2)在C++11中,sizeof (nullptr)==sizeof((void)*)
(3)这里有个问题,nullptr作为一个右值,自然是不能取地址了,但他的类型是什么?

nullptr_t,定义在<cstddef>里面的类。不过nullptr不用include也能用。 C++14标准拟加上一个
is_null_pointer
。判断是不是为nullptr。

0 0
原创粉丝点击