- 自动内存管理
- RAII(Resource Acquisition Is Initialization)资源获取即初始化
- uniqu_ptr
- unique_ptr 可以用于数组。
- unique_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 管理 p
cout << *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; // 输出 10
return 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);//ok
ap->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=100
up->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(); //此处仅将自己所累积的计数减 1
cout<<sp.use_count()<<endl;
sp.reset(); //此时 reset 等价于 sp 对象消失,若己为零,则不再减 1.
}
int main(){
//引用计数,每次被引用引用计数加1,对象消失-1
shared_ptr<int> sp(new int(10));
cout<<*sp<<endl;//10
cout<<"use_count:"<<sp.use_count()<<endl;//use_count:1
shared_ptr<int> sp2(sp);
cout<<*sp2<<endl;//10
cout<<"use_count:"<<sp.use_count()<<endl;//use_count:2
cout<<"use_count:"<<sp2.use_count()<<endl;//use_count:2
return 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;//0
cout<<"+++++++++++++++++++++"<<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;//1
func(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;//3
shared_ptr<A> spm =std::move(sp);
cout<<spm.use_count()<<endl;//3
cout<<sp2.use_count()<<endl;//3
cout<<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+1
cout<<sp.use_count()<<endl;//1
}
int main()
{
shared_ptr<A> sp(new A);
func (sp);
cout<<sp.use_count()<<endl;//1
}