了解 C++ 中的智能指针
本文将讨论 C++ 中的智能指针、它们如何防止内存泄漏、智能指针的类型以及我们应该使用它们的情况。
用 C++ 实现智能指针
我们可以将 C++ 中的智能指针定义为一个类模板,我们可以使用它来维护原始原始指针。我们的智能指针类包含一个指针变量来保存我们的原始指针、析构函数和运算符覆盖方法。
但是,我们不限于仅包括这些字段和方法。我们可以根据需要添加我们的方法。
我们使用这个类来处理指针,而不是直接处理原始指针。除了在 C++ 中为智能指针定义自定义类,我们还可以使用标准 C++ 库。
让我们为 C++ 智能指针实现定义一个自定义类。
#include<iostream>
using namespace std;
template<class T>
class CustomSmartPointer
{
T *data;
public:
explicit CustomSmartPointer (T *ptr = NULL) // Constructor to assign pointer
{
data = ptr;
}
~CustomSmartPointer() // Destructor that deallocated memory
{
delete data;
}
// We overload * and -> operators
T *operator ->()
{
return data;
}
T &operator *()
{
return *data;
}
};
int main()
{
CustomSmartPointer<int> myPtr(new int());
*myPtr = 100;
cout<<*myPtr<<endl;
// After executing above statement, memory allocated to myPtr is deallocated.
return 0;
}
输出:
stark@stark:~/eclipse-workspace/smart_pointer$ g++ custom_smart_prt.cc
stark@stark:~/eclipse-workspace/smart_pointer$ ./a.out
100
使用智能指针析构函数防止 C++ 中的内存泄漏
析构函数的存在使我们的智能指针类与众不同,并将其与原始指针区分开来。我们使用 C++ 智能指针析构函数来释放分配给我们指针的内存。
当类对象超出范围时,会自动调用析构函数并释放分配的内存。如果我们已经自动化了内存释放过程,我们就不必担心我们可能忘记释放的指针导致的资源泄漏。
智能指针析构函数的作用类似于 C++ 中的自动垃圾收集器,类似于 Java 和 C#。
让我们看一个由原始指针引起的资源泄漏的例子。
#include<iostream>
using namespace std;
class student
{
private:
string name;
int marks;
public:
void setMarks(int m)
{
marks = m;
}
void setName(string n)
{
name = n;
}
int getMarks()
{
return marks;
}
string getName()
{
return name;
}
};
int main()
{
while(true)
{
student * p = new student;
*p->name = "Stark";
*p->marks = 100;
}
return 0;
}
如我们所见,我们正在无限循环中初始化学生类型的指针。我们还没有释放指针内存,所以这将继续分配资源,直到所有内存都被占用。
我们不应该长时间执行这个程序。否则,我们的系统可能会因为内存溢出而挂起。
但是,如果我们使用智能指针,内存将在每次循环后自动释放。因此,一次只占用一个指针内存。
C++ 中智能指针的类型
我们在 C++ 中有三种不同类型的智能指针。这些是在 C++ 库中为智能指针实现的类型。
unique_ptr
这种智能指针类型让我们只为底层原始指针分配一个用户。这意味着我们不能将相同的底层指针分配给两个或更多对象。
我们应该默认使用这种类型的指针,直到我们可以共享内存。
shared_ptr
顾名思义,我们可以使用这个智能指针将多个所有者分配给一个原始指针。这使用参考计数器来跟踪受让人的数量。
weak_ptr
这种智能指针类型与 shared_ptr
非常相似,只是它不参与引用计数器。这并不意味着它没有引用计数器,但它的引用不被计数。
相反,我们使用它的引用计数器来计算其他共享引用。当我们不需要严格控制所有权时,我们可以使用这个指针。
它提供对一个或多个 shared_ptr
对象的访问。但是,它有一个优势,因为它消除了死锁的可能性。
让我们看一个 C++ 智能指针实现。
#include<iostream>
#include<memory>
using namespace std;
class student
{
private:
string name;
int marks;
public:
void setMarks(int m)
{
marks = m;
}
void setName(string n)
{
name = n;
}
int getMarks()
{
return marks;
}
string getName()
{
return name;
}
};
int main()
{
unique_ptr<student> ptr1 (new student);
ptr1->setName("Stark");
ptr1->setMarks(100);
cout<<"unique_ptr output >>\n";
cout<<ptr1->getName()<<" : "<<ptr1->getMarks()<<"\n";
cout<<"shared_ptr output >> \n";
shared_ptr<student> ptr2 (new student);
ptr2->setName("Tony");
ptr2->setMarks(99);
cout<<ptr2->getName()<<" : "<<ptr2->getMarks()<<"\n";
shared_ptr<student> ptr22;
ptr22 = ptr2;
cout<<ptr22->getName()<<" : "<<ptr22->getMarks()<<"\n";
cout<<"Reference count of shared_ptr: "<<ptr2.use_count()<<endl;
auto ptr = make_shared<student> ();
ptr->setName("Jarvis");
ptr->setMarks(98);
cout<<"Weak pointer output >>"<<endl;
weak_ptr<student> ptr3;
ptr3 = ptr;
cout<<"Reference count of weak_ptr: "<<ptr3.use_count()<<endl;
shared_ptr<student> ref = ptr3.lock();
cout<<ref->getName()<<" : "<<ref->getMarks()<<"\n";
return 0;
}
输出:
stark@stark:~/eclipse-workspace/smart_pointer$ g++ types_smart.cc
stark@stark:~/eclipse-workspace/smart_pointer$ ./a.out
unique_ptr output >>
Stark : 100
shared_ptr output >>
Tony : 99
Tony : 99
Reference count of shared_ptr: 2
Weak pointer output >>
Reference count of weak_ptr: 1
Jarvis : 98
需要注意的是,弱指针的引用计数是 1,因为它不参与引用计数。
何时在 C++ 中使用智能指针
我们不应该对所有事情都使用智能指针。由于我们为智能指针使用类模板,它们通常会降低性能并增加程序的复杂性。
我们应该将原始指针用于性能关键的应用程序和小程序作为最佳实践。但是,我们应该始终在指针资源使用结束后释放它们。
如果我们的代码很大并且很难手动为每个指针释放内存,我们应该使用智能指针。如果应用程序不是性能关键,我们应该更喜欢使用智能指针。
如果我们需要处理异常、引用计数、释放时间执行,我们应该使用智能指针。
相关文章
在 C++ 中通过掷骰子生成随机值
发布时间:2023/04/09 浏览次数:169 分类:C++
-
本文解释了如何使用时间因子方法和模拟 C++ 中的掷骰子的任意数方法生成随机数。了解它是如何工作的以及它包含哪些缺点。提供了一个 C++ 程序来演示伪数生成器。
在 C++ 中使用模板的链表
发布时间:2023/04/09 浏览次数:158 分类:C++
-
本文解释了使用模板在 C++ 中创建链表所涉及的各个步骤。工作程序演示了一个链表,该链表使用模板来避免在创建新变量时声明数据类型的需要。
在 C++ 中添加定时延迟
发布时间:2023/04/09 浏览次数:142 分类:C++
-
本教程将为你提供有关在 C++ 程序中添加定时延迟的简要指南。这可以使用 C++ 库为我们提供的一些函数以多种方式完成。
在 C++ 中创建查找表
发布时间:2023/04/09 浏览次数:155 分类:C++
-
本文重点介绍如何创建查找表及其在不同场景中的用途。提供了三个代码示例以使理解更容易,并附有代码片段以详细了解代码。
如何在 C++ 中把字符串转换为小写
发布时间:2023/04/09 浏览次数:63 分类:C++
-
介绍了如何将 C++ std::string 转换为小写的方法。当我们在考虑 C++ 中的字符串转换方法时,首先要问自己的是我的输入字符串有什么样的编码
如何在 C++ 中确定一个字符串是否是数字
发布时间:2023/04/09 浏览次数:163 分类:C++
-
本文介绍了如何检查给定的 C++ 字符串是否是数字。在我们深入研究之前,需要注意的是,以下方法只与单字节字符串和十进制整数兼容。
如何在 c++ 中查找字符串中的子字符串
发布时间:2023/04/09 浏览次数:65 分类:C++
-
本文介绍了在 C++ 中检查一个字符串是否包含子字符串的多种方法。使用 find 方法在 C++ 中查找字符串中的子字符串
如何在 C++ 中把字符串转换为 Char 数组
发布时间:2023/04/09 浏览次数:107 分类:C++
-
本文介绍了在 C++ 中把字符串转换为 char 数组的多种方法。使用 std::basic_string::c_str 方法将字符串转换为 char 数组