问:你为什么不用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; //11
unique_ptr<int> up3 = move(up1);
cout << *up3 << endl; //11
cout << *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.指针空值的衍变
#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规则
int *p = (void*)0;//C++会犯错
int *p = nullptr;//C++11可以
(2)在C++11中,sizeof (nullptr)==sizeof((void)*)