C++常见的内存分配方式有三种:
- 从静态存储区分配,这里主要是存储局部static对象,类的static成员以及定义在函数之外的变量;
- 从栈内存分配,这里主要是存储函数内的非static对象;
- 从堆内存动态分配
其中,静态存储区以及栈内存中的对象,都是由编译器自动创建和销毁,而堆内存中的对象都是由程序显示控制的,通常都是new创建delete销毁或者malloc创建free销毁。动态内存的管理非常棘手,如果动态地创建了对象却没有显式得销毁,就会发生内存泄漏;如果在还有指针引用的时候释放了内存就会出现引用非法内存的指针。
C++11提供了两种智能指针用于管理动态对象,他们可以自动的释放所指向的对象,不用再人为显式地手动销毁,他们都定义在memory头文件中:
- shared_ptr,允许多个指针指向同一个对象:
shared_ptr<string> p; //可以指向string的shared_ptr
shared_ptr支持的操作:
void sharedPtrTest(){ //make_shared函数的作用是: // 在堆中分配一个对象并初始化它,并返回指向该对象的shared_ptr shared_ptr<int> p1 = make_shared<int>(0); shared_ptr<int> p2 = make_shared<int>(1); //在条件判断中使用智能指针,相当于检测它是否为空 //如果只能指针没有指向任何内容,返回false,否则返回true if (p1 && p2){ //解引用智能指针,用法与普通指针一样,获得它指向的对象 cout << *p1 << endl;//output:0 //返回p中保存的指针 cout << p2.get() << endl;//output:002FB464(vs2013) //交换,也可以写作p1.swap(p2) swap(p1, p2); cout << *p1 << " " << *p2 << endl; //output: 1 0 } //智能指针的拷贝赋值,递增p1的引用计数,此之后p1被引用2次,p2被引用1次 shared_ptr<int> p3(p1); //返回p1共享智能指针的数量,即p1指向对象被引用次数 cout << p1.use_count() << endl; //output: 2 cout << p2.use_count() << endl; //output: 1 //如果只有自己指向这个对象,返回true,否则false cout << p1.unique() << endl; //output: 0,说明 p1不是独占对象的 cout << p2.unique() << endl; //output: 1,说明p2独占对象 }
再说说引用计数,每个shared_ptr可以看作有一个关联的计数器,保存着这个指针指向的动态内存内的对象被引用的次数,即有多少个智能指针指向它,当变为0即没有指针指向它时这块内存会被自动释放。而只要还有智能指针指向它,它就不会被释放。
- unique_ptr,该指针会独占指向的对象,不允许其他指针引用,用法基本与shared_ptr相同,但是由于它是独占对象,所以不能进行拷贝赋值以及引用计数相关操作。
void uniquePtrTest(){ unique_ptr<int> p1(new int(42)); //p1.release()返回指向该内存指针,将p1置为空,表示p1放弃控制权 //此行代码表示p1转移出去对该对象的所有权给p2,即p1置空返回指针赋值给p2 unique_ptr<int> p2(p1.release()); cout << *p2 << endl; //output:42 unique_ptr<int> p3(new int(10)); //释放p2原指向对象,将p3置空,其指向的对象赋值给p2,reset()也可以没有参数,那么久只释放p2原有对象,不对其赋新值 p2.reset(p3.release()); cout << *p2 << endl; //output:10 }