0.指针的危害
- 指针未初始化
- 野指针
- 内存泄漏
1.智能指针分类
智能指针 | 进入c 标准的版本 | 头文件 | boost头文件 | 说明 |
---|---|---|---|---|
auto_ptr |
c 03 | memory |
|
尽量避免使用 |
unique_ptr |
c 11 | memory |
|
管理单个堆内存对象,独享所有权,不允许赋值和拷贝,不能用于管理数组对象 |
shared_ptr |
c 11 | memory |
|
引用计数智能指针,共享所有权 |
weak_ptr |
c 11 | memory |
|
shared_ptr的观察者,只进行引用而不改变引用计数,用来解决shared_ptr的循环引用问题 |
scoped_ptr |
- | - |
|
作用域智能指针,功能与unique_ptr相似。 |
- 本质:
将指针封装为类对象成员,并在析构函数里删除指针指向的内存。
- 不同:
auto_ptr
、unique_ptr
、scoped_ptr
马上删除。shared_ptr
计数为0删除。weak_ptr
不删除。
智能指针是来解决指针危害的。
1. auto_ptr
-
作用
对作用域内的动态分配对象的自动释放
-
基本类型
#include
#include
using namespace std;
int main(){
int* pn = new int(10);
auto_ptr ap(pn);
cout << *ap << endl;
}
- 类类型
#include
#include
using namespace std;
class test{
public:
test(){
cout << __func__ << endl;}
~test(){
cout << __func__ << endl;}
void func(){
cout << __func__ << endl;}
};
int main(){
test* pt = new test;
auto_ptr apt(pt);
apt->func();
}
通过valgrind可以看到没有内存泄露,指针可以被正常释放。
- 缺陷
- 两个
auto_ptr
不能同时拥有同一个对象
#include
using namespace std;
int main(){
int* pn = new int(10);
auto_ptr ap1(pn);
auto_ptr ap2(pn);
}
auto_ptr
不能管理数组指针
#include
using namespace std;
int main(){
int*pa=new int[10];
auto_ptrap(pa);
}
auto_ptr
被拷贝或被赋值后,失去对原指针的管理.这种情况被称为指针所有权传递。
赋值的情况
#include
#include
using namespace std;
int main(){
int*p = new int(10);
auto_ptr ap1(p);
cout<< *ap1 < ap2=ap1;
cout<< *ap1 <
拷贝的情况
#include
#include
using namespace std;
void func(auto_ptr ap){
cout << *ap << endl;
}
int main(){
int*p = new int(10);
auto_ptr ap(p);
cout<< *ap <
auto_ptr
不能作为容器对象,因为stl容器中的元素经常要支持拷贝,赋值等操作。
#include
#include
#include
using namespace std;
int main(){
int*p = new int(10);
auto_ptr ap(p);
vector > vec;
vec.push_back(ap);
}
2. unique_ptr
- 作用
代替auto_ptr
,不复制与赋值。
3. scoped_ptr
- 作用
与unique_ptr
相似,在本作用域中使用,不能复制与赋值。
4. shared_ptr
循环引用问题
#include
#include
#include
#include
class parent;
class children;
class parent {
public:
~parent() {
std::cout <<"destroying parent\n"; }
public:
boost::shared_ptr children;
};
class children {
public:
~children() {
std::cout <<"destroying children\n"; }
public:
boost::shared_ptr parent;
};
void test(){
boost::shared_ptr father(new parent());
boost::shared_ptr son(new children);
father->children = son;
son->parent = father;
}
void main(){
std::cout<<"begin test...\n";
test();
std::cout<<"end test.\n";
}
5. weak_ptr
解决shared_ptr
循环引用问题
#include
#include
#include
#include
using namespace boost;
class parent;
class children;
class parent {
public:
~parent() {
std::cout <<"destroying parent\n"; }
public:
shared_ptr children;
};
class children {
public:
~children() {
std::cout <<"destroying children\n"; }
public:
weak_ptr parent;
};
void test(){
shared_ptr father(new parent());
shared_ptr son(new children);
father->children = son;
son->parent = father;
}
void main(){
std::cout<<"begin test...\n";
test();
std::cout<<"end test.\n";
}
智能指针weak_ptr
主要用来协助shared_ptr
。不参与引用计数,但是有以下好处:
- 打破递归的依赖关系
- 使用一个共享的资源但是不要所有权,不添加引用计数
- 避免悬空指针。
- 方法一
boost::shared_ptr sp(new std::string("method1");
// 从shared_ptr构建出来
boost::weak_ptrwp(sp);
// 再从shared_ptr获取回去
boost::shared_ptr p = wp.lock();
- 方法二
boost::shared_ptr sp(new std::string("method1");
// 从shared_ptr构建出来
boost::weak_ptrwp(sp);
// 再从shared_ptr获取回去
boost::shared_ptr p(wp);
总结
智能指针的特性
智能指针
管理同一个对象
可拷贝
可复制
所有权
成为容器元素
管理数组指针
auto_ptr
ng
ok
ok
传递
ng
ng
unique_ptr
ng
ng
ng
独享
ng
ng
scoped_ptr
ng
ng
ng
独享 ng
ng
shared_ptr
ng
ok
ok
共享
ok
ng
weak_ptr
ng
ok
ok
共享
ok
ng
虽然通过弱引用指针可以有效的解除循环引用,但这种方式必须在程序员能预见会出现循环引用的情况下才能使用,也可以是说这个仅仅是一种编译期的ag真人游戏的解决方案。
如果程序在运行过程中出现了循环引用,还是会造成内存泄漏的。
因此,不要认为只要使用了智能指针便能杜绝内存泄漏。
内存管理技术
实践
有关智能指针的使用规则
- effective c
条款17:以独立语句将newed对象置于智能 -指针
- effective stl
条款8:永不建立auto_ptr
的容器
- exceptional c
条款37:auto_ptr
- more exceptional c
条款21:未管理指针存在的问题,之二:使用 auto_ptr
?
条款29:使用 auto_ptr
条款30:智能指针成员,之一:auto_ptr
存在的问题
- effective modern c
条款18: 使用std::unique_ptr
来管理独占所有权的资源
条款19: 使用std::shared_ptr
来管理共享所有权的资源
条款20: 使用std::weak_ptr
替换会造成指针悬挂的类std::shared_ptr
指针
条款21: 比起直接使用new
优先使用std::make_unique
和std::make_shared
简单实现智能指针
// #include
#include
using namespace std;
// auto_ptr c 03 c 11以后被废弃
// unique_ptr c 11 ~ scope_ptr boost
// shared_ptr c 11/boost
// weak_ptr c 11/boost
namespace ministl{
template
class auto_ptr{
public:
typedef t value_type;
typedef value_type* pointer;
typedef value_type& reference;
typedef const reference const_reference;
private:
pointer ptr;
public:
auto_ptr(pointer p):ptr(p){
}
auto_ptr(const auto_ptr& p):ptr(p.ptr){
const_cast(p).ptr = null; //
}
auto_ptr& operator=(const auto_ptr& p){
if(this == &p) return *this;
delete ptr;
ptr = p.ptr;
const_cast(p).ptr = null; //
}
~auto_ptr(){
delete ptr;}
reference operator*(){
return *ptr;}
const_reference operator*()const{
return *ptr;}
pointer operator->(){
return ptr;}
const pointer operator->()const{
return ptr;}
};
template
class unique_ptr{
public:
typedef t value_type;
typedef value_type* pointer;
typedef value_type& reference;
typedef const reference const_reference;
private:
pointer ptr;
public:
unique_ptr(pointer p):ptr(p){
}
unique_ptr(const unique_ptr& p) = delete;
unique_ptr& operator=(const unique_ptr& p) = delete;
~unique_ptr(){
delete ptr;}
reference operator*(){
return *ptr;}
const_reference operator*()const{
return *ptr;}
pointer operator->(){
return ptr;}
const pointer operator->()const{
return ptr;}
};
template
class shared_ptr{
struct data{
t* ptr;
size_t count;
data(t* ptr,size_t count):ptr(ptr),count(count){
}
};
data* data;
public:
// explicit 取消单参构造函数等号初始化,不允许隐式转换到该对象
explicit shared_ptr(t* ptr):data(new data(ptr,1)){
}
~shared_ptr(){
data->count--;
if(data->count == 0){
delete data->ptr;
delete data;
}
}
shared_ptr(const shared_ptr& ptr){
data = ptr.data;
data->count ;
}
shared_ptr& operator=(const shared_ptr& ptr){
if(this == &ptr || data == ptr.data) return *this;
data->count--;
if(data->count == 0){
delete data->ptr;
delete data;
}
data = ptr.data;
data->count ;
}
t& operator*(){
return *data->ptr;
}
t* operator->(){
return data->ptr;
}
bool operator==(const shared_ptr& ptr)const{
return data->ptr == ptr.data->ptr;
}
bool operator!=(const shared_ptr& ptr)const{
return data->ptr != ptr.data->ptr;
}
};
};
using namespace ministl;
void func(auto_ptr ap){
cout << *ap << endl;
}
void func(unique_ptr up){
cout << *up << endl;
}
void func(shared_ptr sp){
cout << *sp << endl;
}
class integerptr{
shared_ptr ptr;
public:
integerptr(int n):ptr(new int(n)){
}
void print(){
cout << *ptr << endl;
}
};
int main(){
auto_ptr ap(new int(100));
// func(ap);
// auto_ptr ap2 = ap;
cout << *ap << endl;
unique_ptr up(new int(100));
// func(up);
// unique_ptr up2 = up;
cout << *up << endl;
shared_ptr sp(new int(110));
func(sp);
shared_ptr sp2 = sp;
cout << *sp2 << endl;
cout << *sp << endl;
// 空指针解引用
// int* p = null;
// cout << *p << endl;
integerptr ptr(200);
ptr.print();
integerptr ptr2 = ptr;
ptr2.print();
}