转自:https://blog.csdn.net/cpp_learner/article/details/118912592,chatgpt
1.介绍
智能指针就是帮管理动态分配的内存的,它会帮助我们自动释放new出来的内存,从而避免内存泄漏!使用智能指针可以自动调用对象的析构函数。
例子:
class Test { public:Test() { cout << "Test的构造函数..." << endl; }~Test() { cout << "Test的析构函数..." << endl; }int getDebug() { return this->debug; }private:int debug = 20; };int main() { //Test *test = new Test;shared_ptr<Test> test(new Test);cout << "test->debug:" << test->getDebug() << endl;cout << "(*test).debug:" << (*test).getDebug() << endl;return 0; } //输出结果 Test的构造函数... test->debug:20 (*test).debug:20 Test的析构函数...
智能指针可以像普通指针一样使用-> 和*取内容,是因为 shared_ptr重载了这2个操作符函数:
1.1 get方法
获取智能指针托管的指针地址。但一般不这样用,直接用智能指针操作即可。
// 定义智能指针 shared_ptr<Test> test(new Test);Test *tmp = test.get(); // 获取指针返回 cout << "tmp->debug:" << tmp->getDebug() << endl;// 函数原型 _NODISCARD _Ty * get() const noexcept { // return wrapped pointerreturn (_Myptr);// 直接返回托管的指针 }
1.2 release方法
取消智能指针对动态内存的托管。
// 定义智能指针 shared_ptr<Test> test(new Test);Test *tmp2 = test.release(); // 取消智能指针对动态内存的托管 delete tmp2; // 之前分配的内存需要自己手动释放// 函数原型 _Ty * release() noexcept { // return wrapped pointer and give up ownership_Ty * _Tmp = _Myptr; _Myptr = nullptr;// 将成员指针设置为空return (_Tmp);// 将指针返回外界,由外界来控制是否delete }
1.3 reset方法
重置智能指针托管的内存地址,如果地址不一致,原来的会被析构掉。
// 重置 p.reset() ; 将p重置为空指针,所管理对象引用计数 减1 p.reset(p1); 将p重置为p1(的值),p 管控的对象计数减1,p接管对p1指针的管控 p.reset(p1,d); 将p重置为p1(的值),p 管控的对象计数减1并使用d作为删除器 p1是一个指针!// 交换 std::swap(p1,p2); // 交换p1 和p2 管理的对象,原对象的引用计数不变 p1.swap(p2); // 交换p1 和p2 管理的对象,原对象的引用计数不变
2.shared_ptr 介绍
记录引用特定内存对象的智能指针数量,当复制或拷贝时,引用计数加1,当智能指针析构时,引用计数减1,如果计数为零,代表已经没有指针指向这块内存,那么我们就释放它。
class Person { public:Person(int v) {this->no = v;cout << "构造函数 \t no = " << this->no << endl;}~Person() {cout << "析构函数 \t no = " << this->no << endl;}private:int no; }; int main() { shared_ptr<Person> sp1;shared_ptr<Person> sp2(new Person(2));// 获取智能指针管控的共享指针的数量 use_count():引用计数cout << "sp1 use_count() = " << sp1.use_count() << endl;cout << "sp2 use_count() = " << sp2.use_count() << endl << endl;// 共享sp1 = sp2;cout << "sp1 use_count() = " << sp1.use_count() << endl;cout << "sp2 use_count() = " << sp2.use_count() << endl << endl;shared_ptr<Person> sp3(sp1); // 共同托管cout << "sp1 use_count() = " << sp1.use_count() << endl; // 可以打印引用计数值cout << "sp2 use_count() = " << sp2.use_count() << endl;cout << "sp2 use_count() = " << sp3.use_count() << endl << endl;return 0; }// 输出结果 构造函数 no = 2 sp1 use_count() = 0 sp2 use_count() = 1sp1 use_count() = 2 sp2 use_count() = 2sp1 use_count() = 3 sp2 use_count() = 3 sp2 use_count() = 3析构函数 no = 2
2.1 使用make_shared构建对象
make_shared<类型>(构造函数参数列表); shared_ptr<int> up3 = make_shared<int>(2); // 多个参数以逗号','隔开,最多接受十个 shared_ptr<string> up4 = make_shared<string>("字符串"); shared_ptr<Person> up5 = make_shared<Person>(9); //()内是构造函数的参数
会将对象指针和引用计数指针分配在一起,更高效。
3.注意事项
- 在调用p.release()时会返回该指针,但不会释放p所指的内存,这时返回值就是对这块内存的唯一索引,如果没有使用这个返回值释放内存或是保存起来,这块内存就泄漏了。
- 禁止delete 智能指针get 函数返回的指针。析构时造成重复释放。
- 禁止用任何类型智能指针get 函数返回的指针去初始化另外一个智能指针。具体解释:
//有问题的代码 std::shared_ptr<int> sp1(new int(10)); // 管理一个动态分配的整数 std::shared_ptr<int> sp4(sp1.get()); // 直接使用裸指针构造
sp1.get()
返回一个指向动态分配的整数的裸指针,但 shared_ptr
并不共享控制块和引用计数信息。如果 shared_ptr
通过裸指针构造,两个 shared_ptr
将独立管理同一个指针对象。这会导致两个 shared_ptr
在各自的生命周期结束时尝试释放相同的动态分配对象,从而造成双重释放问题,导致未定义行为(通常程序崩溃)。正确用法:
auto sp1 = std::make_shared<int>(10); auto sp4 = sp1; // 正确: sp4 现在共享 sp1 的控制块和引用计数
通过拷贝构造函数来共享对象的所有权,确保引用计数正确管理对象的生命周期。
- 不要定义指向智能指针的指针,这违背了智能指针的初衷。