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,我们有一个潜在的内存泄漏

显然,只有一个地方的记忆没有被删除。 我们可以在那里添加显式代码来释放原始内存

但关键是,代码中可能存在许多情况,在这些情况下,可能会发生这种情况并忘记释放内存。在处理异常时也可能发生这种情况

但是,如果在所有终止条件下,我们都保证内存将被释放,那会怎样呢

在所有这些情况下,只有一个函数被调用:静态对象的析构函数(不是动态的-非常重要)

因此,我们的想法是赋予持有指向特定类的指针的责任,该类的任务是在调用其析构函数时释放指针持有的内存。 此类称为智能指针<