欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 会展 > C++ 11 智能指针 自动内存管理

C++ 11 智能指针 自动内存管理

2025/9/20 10:22:23 来源:https://blog.csdn.net/gopher9511/article/details/141144349  浏览:    关键词:C++ 11 智能指针 自动内存管理
  • 自动内存管理
  • 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}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词