您的位置:首页 > 娱乐 > 八卦 > 从0开始C++(十一):智能指针

从0开始C++(十一):智能指针

2024/10/5 14:57:54 来源:https://blog.csdn.net/a1547998353/article/details/139987774  浏览:    关键词:从0开始C++(十一):智能指针

目录

概念

作用

auto_ptr(自动指针)

 unique_ptr(唯一指针)

 shared_ptr(共享指针)

weak_ptr(虚指针)

补充:手写一个共享指针类


概念

C++的智能指针是一种用于管理动态分配内存的指针。它是C++语言的一个重要特性,通过自动管理内存资源,帮助开发人员避免内存泄漏和悬空指针的问题。

智能指针的作用是在动态分配内存时提供更方便、更安全的管理方式,使开发人员无需手动释放内存。它们可以跟踪对象的生命周期,并在不再需要时自动释放内存,大大减少了内存泄漏的可能性。

作用

智能指针有以下几个主要作用:

  1. 自动释放内存:智能指针使用了RAII(资源获取即初始化)的原则,即在初始化时获取资源,在对象销毁时自动释放资源。这样可以确保在离开作用域时,分配的内存会被正确释放。

  2. 简化内存管理:智能指针隐藏了手动释放内存的细节,减少了开发人员的工作量和出错的机会。开发人员无需记住所有动态分配内存的位置,也无需手动调用delete释放内存。

  3. 避免悬空指针问题:悬空指针是指指向已释放内存的指针,使用悬空指针可能导致未定义行为或程序崩溃。智能指针通过在对象不再使用时自动释放内存,有效地避免了悬空指针问题。

  4. 解决资源泄漏问题:使用智能指针,资源的释放与其生命周期绑定,确保资源在不再需要时被正确释放。这可以帮助避免资源泄漏,如忘记释放内存、文件句柄或其他系统资源。

总之,C++的智能指针在动态内存管理方面发挥了重要作用,提供了更安全、更方便的内存管理方式。通过使用智能指针,可以减少内存泄漏和悬空指针问题,提高代码的可靠性和可维护性。

 C++四种智能指针

● auto_ptr(自动指针)C++98 已废弃)

● unique_ptr(唯一指针)C++11)

● shared_ptr(共享指针)C++11)

● weak_ptr(虚指针)C++11)

使用智能指针需要引入对应头文件 #include<memory> 

auto_ptr(自动指针)

auto_ptr是C++98标准中提供的一种智能指针,用于管理动态分配的对象。它的使用方式如下:

1、创建auto_ptr对象:

可以使用auto_ptr模板类创建auto_ptr对象。

auto_ptr<T> ptr(new T);

其中,T是所要管理对象的类型,new T会动态分配内存并返回指向这个新对象的指针。

2、使用auto_ptr对象:

ptr.get()->MemberFunction(); //取出被管理的堆内存对象,并调用成员函数

3、所有权转移:

auto_ptr的一个特点是所有权转移,当将一个auto_ptr赋值给另一个auto_ptr时,原来的auto_ptr将不再管理对象。

auto_ptr<T> ptr1(new T); // 创建auto_ptr对象ptr1
auto_ptr<T> ptr2; // 创建auto_ptr对象ptr2ptr2 = ptr1; // 所有权从ptr1转移到ptr2,ptr1不再管理对象

需要注意的是,一旦所有权转移,原来的auto_ptr将变为空指针,并且不应再对其进行解引用或操作。

4、离开作用域的自动销毁:

当auto_ptr对象超出其作用域时,它所管理的对象将会被自动删除。

{auto_ptr<T> ptr(new T); // 在作用域内创建auto_ptr对象// 使用ptr对象
} // 在作用域结束时,ptr对象会被销毁,所管理的对象也会被自动释放

auto_ptr的析构函数会调用delete操作符来释放对象内存,因此不适用于管理动态分配的数组和其他类型的资源。

总而言之,auto_ptr的使用方式包括创建auto_ptr对象、使用auto_ptr对象、所有权转移和离开作用域自动销毁。但由于其存在一些问题,建议使用C++11及以上版本提供的更安全和更强大的智能指针类型,如unique_ptr和shared_ptr。

 unique_ptr(唯一指针)

unique_ptr是C++11引入的一种智能指针,用于管理动态分配的对象。与auto_ptr相比,unique_ptr具有更安全和更强大的功能。它的使用方式和auto_ptr几乎一样,只有权限转移时操作有所区别。

使用move函数来进行所有权转移。

unique_ptr<T> ptr1(new T); // 创建unique_ptr对象ptr1
unique_ptr<T> ptr2; // 创建unique_ptr对象ptr2ptr2 = move(ptr1); // 所有权从ptr1转移到ptr2,ptr1不再管理对象

unique_ptr提供了更安全和更灵活的资源管理功能,是C++中推荐使用的智能指针类型之一。

 

shared_ptr(共享指针)

shared_ptr是C++11引入的一种智能指针,用于管理动态分配的对象。不同于unique_ptr,shared_ptr允许多个指针共享同一个对象,并且会跟踪对象的引用计数。当引用计数为0时,对象会被自动删除。以下是shared_ptr的使用方式:

1、创建shared_ptr对象: 可以使用shared_ptr模板类创建shared_ptr对象。

shared_ptr<T> ptr(new T);

其中,T是所要管理对象的类型,new T会动态分配内存并返回指向这个新对象的指针。

2、使用shared_ptr对象: 

ptr.get()->MemberFunction(); //取出被管理的堆内存对象,并调用成员函数

3、共享所有权:

shared_ptr的最大特点是可以共享所有权,即多个shared_ptr对象可以指向同一个对象。当最后一个指向对象的shared_ptr被销毁时,对象才会被自动删除。

shared_ptr<T> ptr1(new T); // 创建shared_ptr对象ptr1
shared_ptr<T> ptr2 = ptr1; // ptr2也指向ptr1所管理的对象// 使用ptr1和ptr2对象

4、获取引用计数: 可以使用 shared_ptr 的 use_count() 函数获取当前共享对象的引用计数。

int count = ptr.use_count(); // 获取ptr对象所管理对象的引用计数

5、离开作用域的自动销毁: 当最后一个指向对象的shared_ptr离开其作用域时,对象将会被自动删除

{std::shared_ptr<T> ptr(new T); // 在作用域内创建shared_ptr对象// 使用ptr对象
} // 在作用域结束时,ptr对象会被销毁,如果没有其他shared_ptr指向对象,则对象也会被自动释放

 

weak_ptr(虚指针)

weak_ptr是C++11引入的一种智能指针,用于解决循环引用的问题。与shared_ptr不同,weak_ptr是一种弱引用,它不会增加对象的引用计数,也不会拥有对象的所有权。以下是weak_ptr的使用方式:

1、创建weak_ptr对象: 可以使用weak_ptr模板类创建weak_ptr对象。

std::weak_ptr<T> ptr;

2、创建weak_ptr对象并与shared_ptr对象绑定: 可以使用shared_ptr的成员函数lock()创建一个weak_ptr对象,并与一个shared_ptr对象绑定。

shared_ptr<T> sharedPtr(new T);
weak_ptr<T> weakPtr = sharedPtr;

3、使用weak_ptr对象:

使用weak_ptr对象的方式与使用shared_ptr对象相似,可以使用lock()函数获取一个shared_ptr对象,从而访问weak_ptr所指向的对象。

shared_ptr<T> sharedPtr = weakPtr.lock(); // 获取一个shared_ptr对象
if (sharedPtr) {// 使用sharedPtr对象
}

lock()函数会返回一个指向共享对象的 shared_ptr ,如果 weak_ptr 已经过期(即其所指向的对象已被释放),则lock()函数返回一个空的shared_ptr。

4、检查 weak_ptr 是否过期: 可以使用 expired() 函数检查 weak_ptr 是否过期,即其所指向的对象是否已被释放。

if (weakPtr.expired()) {// weakPtr已过期,所指对象已释放
}

5、使用weak_ptr解决循环引用: 当需要解决循环引用问题时,可以使用weak_ptr和shared_ptr组合使用。其中,有一个shared_ptr作为主要的引用,而另一个shared_ptr使用weak_ptr进行引用,这样就打破了循环引用。

#include <iostream>
#include <memory>using namespace std;class B;class A {
public:weak_ptr<B> bPtr; // 引入weak_ptr~A() {cout << "A destructor called" << endl;}
};class B {
public:weak_ptr<A> aPtr; // 引入weak_ptr~B() {cout << "B destructor called" << endl;}
};int main() {shared_ptr<A> aPtr = make_shared<A>();shared_ptr<B> bPtr = make_shared<B>();aPtr->bPtr = bPtr; // 将bPtr赋值给aPtr的weak_ptr成员bPtr->aPtr = aPtr; // 将aPtr赋值给bPtr的weak_ptr成员return 0;
}

 

补充:手写一个共享指针类

#include <iostream>
#include <memory>   // 智能指针头文件
using namespace std;template<class T>
class SharedPtr
{
private:T *res = NULL;  // 资源指针int *count = NULL;  // 引用计数public:SharedPtr(T *t):res(t),count(new int(1)){}// 拷贝构造函数SharedPtr(const SharedPtr &sp):res(sp.res),count(sp.count){(*count)++; // 计数+1}// 赋值运算符重载SharedPtr &operator =(const SharedPtr &sp){if(&sp != this){// 销毁原来的资源reset();res = sp.res;count = sp.count;(*count)++;}return *this;}void reset(){(*count)--; // 计数-1if(*count == 0){delete res;delete count;}res = NULL;count = NULL;}T* get()const{return res;}int use_count()const{return *count;}~SharedPtr(){reset();}
};class Test
{
private:string s;
public:Test(string s):s(s){cout << s << "构造函数" << endl;}~Test(){cout << s << "析构函数" << endl;}void show(){cout << s << "执行程序" << endl;}
};int main()
{SharedPtr<Test> sp1(new Test("A")); // 构造函数sp1.get()->show();cout << sp1.use_count() << endl;    // 1SharedPtr<Test> sp2(sp1); // 拷贝构造函数cout << sp2.use_count() << endl;    // 2SharedPtr<Test> sp3(new Test("B"));cout << sp3.use_count() << endl;    // 1sp3 = sp2;  // 赋值运算符重载sp3.get()->show();cout << sp3.use_count() << endl;    // 3return 0;
}

 

版权声明:

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

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