- 自动内存管理
- RAII(Resource Acquisition Is Initialization)资源获取即初始化
- auto_ptr的弃用
- uniqu_ptr
- unique_ptr 可以用于数组。
- unique_ptr 常用接口
- reset
- unique_ptr 移动
- shared_ptr
- 常用接口
- 引用计数
- shared_ptr单独的引用计数
- shared_ptr 移动
- shared_ptr 引用传递
自动内存管理
RAII(Resource Acquisition Is Initialization)资源获取即初始化
是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。
RAII 的一般做法是这样的:
在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,
最后在对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。这种做法有两大好处:
①不需要显式地释放资源。
②采用这种方式,对象所需的资源在其生命期内始终保持有效。此时,所托管的资源,随对象的创建而获取,随对象的消失而消失,
即所谓的 RAII思想:资源获取即初始化。
#include <iostream>
#include <memory>
using namespace std;class A{
public:A(){cout<<"A()"<<endl;}~A(){cout<<"~A()"<<endl;}void dis(){cout<<"A::void dis()"<<endl;}
};
void func(){auto_ptr<A> ap(new A);ap->dis();}int main(){func();
}
原理上,是代理了被托管的对象指针,管理对象的生命周期,即实现自动释放。其
行为类似于所托管的对象指针,原因是,重载了 operator->和 operator*。
auto_ptr的弃用
#include <iostream>
#include <memory>
using namespace std;int main()
{int *p = new int(10); // 动态分配一个 int,初始值为 10{unique_ptr<int> up(p); // 使用 unique_ptr 管理 pcout << *up << endl; // 输出 10} // up 超出作用域,自动释放 p// 这里再次使用 p 会导致未定义行为,因为 p 已经被释放unique_ptr<int> up2(p); // 这行代码会导致错误cout << *up2 << endl;// 正确的做法是直接使用 unique_ptr 管理动态内存unique_ptr<int> up3(new int(10));cout << *up3 << endl; // 输出 10return 0;
}
uniqu_ptr
uniqu_ptr 的使用方法,基本上等同于 auto_ptr, 不同之处,就在于实现了资源的
唯一, 既不可以拷贝也不可以赋值。
#include <iostream>
#include <memory>
using namespace std;class A{
public:A(){cout<<"A()"<<endl;}~A(){cout<<"~A()"<<endl;}void dis(){cout<<"A::void dis()"<<endl;}
};
void func(){unique_ptr<A> ap(new A);//okap->dis();unique_ptr<A> ap2(ap);//编译不过ap2->dis();
}int main(){func();
}
unique_ptr 可以用于数组。
#include <iostream>
#include <memory>
using namespace std;class A {
public:// 构造函数A() {cout << "A()" << endl; // 输出构造函数被调用的信息}// 析构函数~A() {cout << "~A()" << endl; // 输出析构函数被调用的信息}// 成员函数,用于显示信息void dis() {cout << "A::void dis()" << endl; // 输出成员函数被调用的信息}
};int main() {// 创建一个 unique_ptr 智能指针,指向一个包含10个整数的数组,并初始化前四个元素unique_ptr<int[]> up(new int[10]{1, 2, 3, 4});// 遍历数组并输出每个元素的值for (int i = 0; i < 10; i++)cout << up[i] << endl;// 创建一个 unique_ptr 智能指针,指向一个包含20个A类对象的数组unique_ptr<A[]> up2(new A[20]);// 遍历数组并调用每个A类对象的dis()成员函数for (int i = 0; i < 20; i++)up2[i].dis();return 0; // 返回0,表示程序正常结束
}
unique_ptr 常用接口
#include <iostream>
#include <memory>
using namespace std;class Copy {
public:// 构造函数,接受一个整数参数Copy(int i) : _i(new int(i)) {cout << "Copy(int i) " << "this: " << this << " _i " << _i << endl; // 输出构造函数被调用的信息}// 拷贝构造函数Copy(const Copy &another) : _i(new int(*another._i)) {cout << " Copy(const Copy & another)" << endl; // 输出拷贝构造函数被调用的信息}// 析构函数~Copy() {cout << " ~Copy() " << this << endl; // 输出析构函数被调用的信息}// 成员函数,用于显示信息void dis() {cout << "Copy::void dis()" << endl; // 输出成员函数被调用的信息}int *_i; // 指向动态分配内存的指针
};int main() {// 创建一个 unique_ptr 智能指针,托管一个新创建的 Copy 对象unique_ptr<Copy> up(new Copy(1));// 检查 unique_ptr 是否托管了资源if (!up) {cout << "无资源" << endl;} else {cout << "有资源" << endl;}// 获取托管资源的指针cout << up.get() << endl; // 输出托管资源的指针地址// 放弃托管,返回资源指针Copy *c = up.release();// 手动释放资源delete c;return 0; // 返回0,表示程序正常结束
}
reset
#include <iostream>
#include <memory>
using namespace std;class Copy {
public:// 构造函数,接受一个整数参数Copy(int i) : _i(new int(i)) {cout << "Copy(int i) " << "this: " << this << " _i " << _i << endl; // 输出构造函数被调用的信息}// 拷贝构造函数Copy(const Copy &another) : _i(new int(*another._i)) {cout << " Copy(const Copy & another)" << endl; // 输出拷贝构造函数被调用的信息}// 析构函数~Copy() {cout << " ~Copy() " << this << endl; // 输出析构函数被调用的信息}// 成员函数,用于显示信息void dis() {cout << "Copy::void dis()" << endl; // 输出成员函数被调用的信息}int *_i; // 指向动态分配内存的指针
};int main() {{// 创建一个 unique_ptr 智能指针,托管一个新创建的 Copy 对象unique_ptr<Copy> up(new Copy(1));// 重置 unique_ptr,托管一个新的 Copy 对象,旧的资源会被释放up.reset(new Copy(2));// 重置 unique_ptr,不托管任何资源,旧的资源会被释放up.reset();cout << "{}内" << endl; }cout << "{}外" << endl; return 0;
}
unique_ptr 移动
//todo unique_ptr 智能指针
#include <iostream>
#include <memory>
using namespace std;class Copy
{
public:Copy(int i):_i(new int(i)){cout<<"Copy(int i) "<<"this: "<<this<<" _i "<<_i<<endl;}Copy(const Copy & another):_i(new int(*another._i)){cout<<" Copy(const Copy & another)"<<endl;}~Copy(){cout<<" ~Copy() "<<this<<endl;}// 成员函数,用于显示信息void dis() {cout << "Copy::void dis() _i="<< *_i << endl; // 输出成员函数被调用的信息}int *_i;
};int main(){unique_ptr<Copy> up(new Copy(100));unique_ptr<Copy> up2=std::move(up);up2->dis();//Copy::void dis() _i=100up->dis();//up此时不再可用return 0;}
shared_ptr
uinque_ptr 解决了 auto_ptr 中引用同一个对象的问题,方式就是不可引用同一个对象。
shared_ptr 解决了 auto_ptr 中引用同一个对象,共同拥有一个资源,
但不会重析构的问题,
原理是,在内部保持一个引用计数,并且仅当引用计数为 0 才能被删除,不可以用数组。
常用接口
引用计数
//todo shared_ptr 智能指针
#include <iostream>
#include <memory>
using namespace std;void func(shared_ptr<int> sp)
{
//sp.reset(); //此处仅将自己所累积的计数减 1cout<<sp.use_count()<<endl;sp.reset(); //此时 reset 等价于 sp 对象消失,若己为零,则不再减 1.
}
int main(){//引用计数,每次被引用引用计数加1,对象消失-1shared_ptr<int> sp(new int(10));cout<<*sp<<endl;//10cout<<"use_count:"<<sp.use_count()<<endl;//use_count:1shared_ptr<int> sp2(sp);cout<<*sp2<<endl;//10cout<<"use_count:"<<sp.use_count()<<endl;//use_count:2cout<<"use_count:"<<sp2.use_count()<<endl;//use_count:2return 0;}
shared_ptr单独的引用计数
#include <iostream>
#include <memory>
using namespace std;
class A
{
public:A(){cout<<"A()"<<this<<endl;}~A(){cout<<"~A()"<<this<<endl;}void dis(){cout<<"A::void dis()"<<endl;}
};int main()
{{//创建一个 shared_ptr 智能指针,托管一个新创建的 A 对象shared_ptr<A> sp(new A);//创建两个 shared_ptr 智能指针,共享同一个托管对象shared_ptr<A> sp2(sp);shared_ptr<A> sp3(sp);//输出当前托管对象的引用计数cout<<sp.use_count()<<endl;//重置 shared_ptr,减少引用计数,但不会影响其他 shared_ptr 的引用计数sp.reset();sp.reset();sp.reset();cout<<sp.use_count()<<endl;//0cout<<"+++++++++++++++++++++"<<endl;}cout<<"======================"<<endl;}
输出
A()0x1544ddb1760
3
0
+++++++++++++++++++++
~A()0x1544ddb1760
======================
示例1
#include <iostream>
#include <memory>
using namespace std;
class A
{
public:A(){cout<<"A()"<<this<<endl;}~A(){cout<<"~A()"<<this<<endl;}void dis(){cout<<"A::void dis()"<<endl;}
};void func(shared_ptr<A> sp){sp.reset();//此时已经取消托管后面的sp.reset();无用sp.reset();cout<<sp.use_count()<<endl;//2
}
int main()
{shared_ptr<A> sp(new A);cout<<sp.use_count()<<endl;//1func(sp);cout<<sp.use_count()<<endl;//1
}
示例2
#include <iostream>
#include <memory>
using namespace std;
class A
{
public:A(){cout<<"A()"<<this<<endl;}~A(){cout<<"~A()"<<this<<endl;}void dis(){cout<<"A::void dis()"<<endl;}
};void func(shared_ptr<A> sp){if(sp.unique()){cout<<"true"<<endl;} else{cout<<"false"<<endl;//输出:false}sp.reset();//此时已经取消托管后面的sp.reset();无用sp.reset();cout<<sp.use_count()<<endl;//2
}
int main()
{shared_ptr<A> sp(new A);cout<<sp.use_count()<<endl;//1//判断sp托管是否唯一if(sp.unique()){cout<<"true"<<endl;//true}func(sp);cout<<sp.use_count()<<endl;//1
}
shared_ptr 移动
//todo shared_ptr 移动
#include <iostream>
#include <memory>
using namespace std;
class A
{
public:A(){cout<<"A()"<<this<<endl;}~A(){cout<<"~A()"<<this<<endl;}void dis(){cout<<"A::void dis()"<<endl;}
};int main()
{shared_ptr<A> sp(new A);shared_ptr<A> sp2(sp);shared_ptr<A> sp3(sp);cout<<sp.use_count()<<endl;//3shared_ptr<A> spm =std::move(sp);cout<<spm.use_count()<<endl;//3cout<<sp2.use_count()<<endl;//3cout<<sp3.use_count()<<endl;//3}
shared_ptr 引用传递
//todo shared_ptr 移动
#include <iostream>
#include <memory>
using namespace std;
class A
{
public:A(){cout<<"A()"<<this<<endl;}~A(){cout<<"~A()"<<this<<endl;}void dis(){cout<<"A::void dis()"<<endl;}
};void func(shared_ptr<A>& sp){ //引用传递,,不用引用会use_count+1cout<<sp.use_count()<<endl;//1
}
int main()
{shared_ptr<A> sp(new A);func (sp);cout<<sp.use_count()<<endl;//1}