【发布时间】:2019-08-15 18:40:04
【问题描述】:
之前已经讨论过智能指针和原始指针之间的区别(例如When should I use raw pointers over smart pointers?),但我无法从我最近一天阅读的材料中得到这个问题的答案。
我有一个类A,它有一个指向某些数据的指针int* a。在我正在考虑的上下文中,a 指向的值可能会在程序中的其他地方使用,因此A 对a 没有所有权,它只是引用它。例如,一个房子存在(例如int h)并且一个人(即班级)有一个对其房子的引用(例如int* my_h)。
我处理这个问题的第一种方法是不使用智能指针,但我很好奇在这个例子中使用智能指针的好处。我怀疑没有多少,因为所有权确实不是什么大问题,而且我没有打电话给new 和delete。
带有原始指针的示例:
#include<iostream>
class A{
public:
A(int a_val){
std::cout << "Creating A instance ";
a = &a_val;
std::cout << "with a = " << *a << std::endl;
};
private:
int* a;
};
int main()
{
int x = 5;
std::cout << "x is " << x << std::endl;
A a(x);
return 0;
}
这里,a 有原始指针int* a,它被分配给main() 中的&x。
智能指针示例(unique_ptr):
#include<memory>
#include<iostream>
class A{
public:
A(std::unique_ptr<int> a_val){
std::cout << "Creating A instance ";
a = std::move(a_val);
std::cout << "with a = " << *a << std::endl;
};
private:
std::unique_ptr<int> 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;
}
unique_ptr 的使用对我来说似乎有点矫枉过正,并且不利于可读性或性能。对吗?
编辑
正如 cmets 中指出的 (...),原始示例存在许多问题。原始指针示例应该是:
#include<iostream>
class A{
public:
A(int* a_val){
std::cout << "Creating A instance ";
a = a_val;
std::cout << "with a = " << *a << std::endl;
};
private:
int* a;
};
int main()
{
int x = 5;
std::cout << "x is " << x << std::endl;
A a(&x);
return 0;
}
智能指针示例可能应该使用shared_ptr。
更具体地说,我对这种扩展到大量类实例的情况感兴趣,这些实例具有指向其他地方定义的数据结构的指针(或指针向量)。例如,在基于代理的模型中,代理有时需要“找到”另一个代理,因此(在我的理解中)可以使用指针向量来指代某个特定代理应该“了解”的其他代理。代理本身将在代理类之外创建。
【问题讨论】:
-
一个区别是您的原始指针版本不起作用。您分配一个指向临时变量的指针,该临时变量在构造函数完成后立即死亡。这突出了原始指针和智能指针之间的一个非常重要的区别 - 智能指针可以防止大多数此类错误。
-
确实,YKsisarvinen 说的很对!您应该将构造函数声明为 A(int* a_val) 并在主体中有 a = a_val;用 A a(&x) 从 main 构造。
-
只是稍微相关,我还将智能指针初始化移动到它所属的位置; ctor 的成员初始化列表。现在你不必要地使用默认构造和移动赋值。合身和形式,我猜。
-
@Yksisarvinen 这不是使用智能指针的理由。 OP所犯的错误与此无关。
-
每个程序员在取消引用指针之前都必须问自己的一个问题是,“我怎么知道这个指针是有效的,即取消引用它不会调用未定义的行为?”使用原始指针,您可能必须检查整个程序的行为以说服自己它保证是有效的;使用智能指针,您只需要检查它是否为非空。
标签: c++ smart-pointers