C++ 对于指针类成员,使用智能指针比使用原始指针有什么好处?
之前已经讨论过智能指针和原始指针之间的区别(例如),但我无法从我最近一天左右阅读的材料中得到这个问题的答案 我有一个类C++ 对于指针类成员,使用智能指针比使用原始指针有什么好处?,c++,smart-pointers,C++,Smart Pointers,之前已经讨论过智能指针和原始指针之间的区别(例如),但我无法从我最近一天左右阅读的材料中得到这个问题的答案 我有一个类a,它有一个指向某些数据的指针int*a。在我考虑的上下文中,a指向的值可能会在程序中的其他地方使用,因此a对a没有所有权,它只是引用它。例如,房子存在(例如inth),而一个人(即阶级)有一个对他们房子的引用(例如int*my_h) 我处理这个问题的第一种方法是不使用智能指针,但我很好奇在这个例子中使用智能指针的好处。我怀疑没有太多,因为所有权真的不是什么大问题,我也没有打电话
a
,它有一个指向某些数据的指针int*a
。在我考虑的上下文中,a
指向的值可能会在程序中的其他地方使用,因此a
对a
没有所有权,它只是引用它。例如,房子存在(例如inth
),而一个人(即阶级)有一个对他们房子的引用(例如int*my_h
)
我处理这个问题的第一种方法是不使用智能指针,但我很好奇在这个例子中使用智能指针的好处。我怀疑没有太多,因为所有权真的不是什么大问题,我也没有打电话给new
和delete
使用原始指针的示例如下:
#包括
甲级{
公众:
A(int A_val){
标准::cout
我很好奇在这个例子中使用智能指针的好处
取决于您正在谈论的智能指针:
unique\u ptr
:您不能将此项用于您的用例,因为这意味着您拥有该对象
shared_ptr
:这会起作用,但您需要在任何地方使用shared_ptr
,并将其生命周期与您的类联系起来
weak_ptr
:与上面相同,但这不会限制生命周期(它可能同时被其他人破坏)
- 其他一些非标准智能指针:取决于
一般来说:如果您只需要保留对对象的引用,请使用引用或指针。当然,您必须确保引用/指针保持有效,这可能是微不足道的,也可能是噩梦,具体取决于程序的设计
我很好奇在这个例子中使用智能指针的好处
取决于您正在谈论的智能指针:
unique\u ptr
:您不能将此项用于您的用例,因为这意味着您拥有该对象
shared_ptr
:这会起作用,但您需要在任何地方使用shared_ptr
,并将其生命周期与您的类联系起来
weak_ptr
:与上面相同,但这不会限制生命周期(它可能同时被其他人破坏)
- 其他一些非标准智能指针:取决于
一般来说:如果您只需要保留对对象的引用,请使用引用或指针。当然,您必须确保引用/指针保持有效,这可能是微不足道的,也可能是噩梦,具体取决于您的程序设计。正如@YKsisarvinen在评论中指出的那样
一个区别是原始指针版本不起作用。您将指针分配给一个临时变量,该变量在构造函数完成后立即消失。这突出了原始指针和智能指针之间的一个非常重要的区别-智能指针可以防止您犯大多数此类错误
一种可能的方法是存储对其他人拥有的对象的引用
struct A
{
A(int& a_val) : a(a_val) {}
int& a;
};
但是,这将阻止您分配对象
int i = 10;
int j = 20;
A a1(i);
A a2(j);
a1 = a2; // This will be an error.
你可以用它来克服这个障碍
struct A
{
A(int& a_val) : a(a_val) {}
std::refernce_wrapper<int> a;
};
结构A
{
A(int&A_val):A(A_val){}
标准::参考包装a;
};
正如@YKsisarvinen在评论中指出的那样
一个区别是原始指针版本不起作用。您将指针分配给一个临时变量,该变量在构造函数完成后立即消失。这突出了原始指针和智能指针之间的一个非常重要的区别-智能指针可以防止您犯大多数此类错误 一种可能的方法是存储对其他人拥有的对象的引用
struct A
{
A(int& a_val) : a(a_val) {}
int& a;
};
但是,这将阻止您分配对象
int i = 10;
int j = 20;
A a1(i);
A a2(j);
a1 = a2; // This will be an error.
你可以用它来克服这个障碍
struct A
{
A(int& a_val) : a(a_val) {}
std::refernce_wrapper<int> a;
};
结构A
{
A(int&A_val):A(A_val){}
标准::参考包装a;
};
主要问题是:谁拥有指针。在本例中:
int main()
{
std::unique_ptr<int> x = std::make_unique<int> (5);//int x = 5;
std::cout << "x is " << *x << std::endl;
A a(std::move(x));
return 0;
}
因此,返回的
A
现在拥有指针,并在指针本身被销毁时将其销毁。主要问题是:谁拥有指针。在本例中:
int main()
{
std::unique_ptr<int> x = std::make_unique<int> (5);//int x = 5;
std::cout << "x is " << *x << std::endl;
A a(std::move(x));
return 0;
}
因此,返回的
A
现在拥有指针,并在指针本身被破坏时将其破坏。即使在开始讨论智能指针的好处之前,我建议您理解为什么需要智能指针。首先,智能指针决不是要取代所有原始指针的使用。它们的设计非常复杂特定用途:内存管理,即清理/释放动态分配的内存
现在假设我们有一个简单的函数,如下所示:
1. void func()
2. {
3. SomeResource* raw_sr = new SomeResource(); //--->Memory allocated here.
4. .
5. .
6. if(someCondition==false)
7. return;
8.
9. delete raw_sr;
10. return;
11.}
上述功能可通过两种方式终止:
1.从第10行返回。-->正常终止
2.从第7行返回。-->在某些错误条件下终止
在第一种情况下,我们清除了记忆。
但是对于情况2,由于没有释放原始的_sr,我们有一个潜在的内存泄漏
显然,只有一个地方的记忆没有被删除。
我们可以在那里添加显式代码来释放原始内存
但关键是,代码中可能存在许多情况,在这些情况下,可能会发生这种情况并忘记释放内存。在处理异常时也可能发生这种情况
但是,如果在所有终止条件下,我们都保证内存将被释放,那会怎样呢
在所有这些情况下,只有一个函数被调用:静态对象的析构函数(不是动态的-非常重要)
因此,我们的想法是赋予持有指向特定类的指针的责任,该类的任务是在调用其析构函数时释放指针持有的内存。
此类称为智能指针<