指针、参考还是智能指针?
Posted
技术标签:
【中文标题】指针、参考还是智能指针?【英文标题】:Pointer,Reference or Smartpointer? 【发布时间】:2015-01-24 14:25:33 【问题描述】:我有以下问题:
假设我有一个包含 100 个对象的向量,因此创建一个副本会很糟糕。
class MyClass
private:
vector<MyObject> mVector;
;
//return by reference
vector<object>& MyClass::GetVector1()
return mVector;
vector<object>* MyClass::GetVector2()
return &mVector;
;
通过引用返回速度很快并且不生成副本。 该向量在 MyClass 中应该仍然可用,因此我不想移动它。 但是使用这个 GetVector() 方法的最佳方法是什么?:
class MyOtherClass
private:
vector<MyObject>* myVector;
vector<MyObject>& myVector2;
vector<MyObject> myVector3;
MyClass m;
;
myVector2 = m.GetVector1(); //only works in an initializer list!
但是如果在创建对象时我无法初始化向量怎么办? 假设我有一个 OnInit() 方法,它会在需要时调用:
void MyOtherClass::OnInit()
myVector = m.GetVector2(); //no copy using return by reference
myVector = &m.GetVector1(); //no copy returning a pointer
myVector3 = m.GetVector1(); //copy
很多人告诉我使用像 myVector 这样的指针非常糟糕,但为什么?????? 我应该改用 smart_pointers 吗? (请给我一个例子,如何使用上面给定的代码)
或者有没有更好的方法来获得快速的性能?
编辑:
对于答案,请检查我在下面选择的答案。
另外我想添加移动语义。
但这在很大程度上取决于代码的用途,有时你真的想复制,你将无法避免它。如果您知道对象的持续时间比跟踪它的代码长,那么只要您希望更改也适用,指针就可以了,否则使用 const ref。
如果您不再需要返回的对象并且它可能会被破坏,则可以使用按值返回,这没关系,因为编译器可能会通过移动来优化它,但您可以显式使用移动语义并移动类中的向量,因为向量元素是动态分配的并且容器是可移动的。检查此链接:Is returning by rvalue reference more efficient?
【问题讨论】:
不要将智能指针视为指针,而是根据所包含指针的所有权来看待它们。 你为什么不让告诉你的人详细说明? 所以我必须使用指针或引用,但原始指针不是坏的吗? @slei:如果您尝试使用它们来管理所有权或指向可能被破坏的事物,它们会很糟糕。如果您只是想指向比指针寿命更长的东西,它们还不错。 在其他论坛有人告诉我,这样的指针可能会导致意外的错误,这应该是一个更好的解决方案:(使用无容器的示例)std::shared_ptr<const std::string> _test; const std::shared_ptr<const std::string>& GetTest() const return _test;
【参考方案1】:
公共对象很好
那时只有一个公共对象。你不需要那个getter:
struct X
std::vector<Y> vec;
X(..) : vec(..) ..
;
那么你可以简单地使用它:
X x(..);
x.vec.some_member_function();
auto& z = x.vec;
z.vec.some_member_function();
如果你真的需要
如果你真的需要使用成员函数版本,那么就使用按引用返回,这有点惯用,尽管它在性能方面与按指针返回基本相同:
vector<Y>& X::GetVector()
return mVector;
然后将其用作:
X x(..);
x.GetVector().some_member_function();
auto& z = x.GetVector();
z.some_member_function();
智能指针不适用于此
智能指针解决了处理资源和描述所有权的问题。在这种情况下,考虑到std::vector
已经在内部拥有并处理自己的资源,它们没有多大意义。
【讨论】:
但是如果向量应该在全班都可用呢? @slei 在这两种情况下,该向量在整个班级中都可用。你到底是什么意思? 为了使 z 在整个类中可用,我将放在标题中:然后在 .cpp 中对其进行初始化,但使用引用变量仅允许在构造函数中使用初始化列表对其进行初始化 第二种带有getter的方法不仅仅是惯用的,它提供了一种非常有用的方法来跟踪将来对该变量的访问。您可以在 Get 方法上设置断点,或者进行一些快速的状态验证,但以后不能轻易地对公共成员进行更改。 @slei 在所有示例中,z
只是对存储在类之外某处的向量的引用。 x
也是类 X
的一个实例。在我的示例中,您可以使用标识符vec
访问类中的向量。【参考方案2】:
如果myVector
可以被初始化列表初始化,那就去做吧!否则你必须使用指针。
指针还不错,只是比引用的限制更少。如果myVector
接受 nullptr/0 值,则可以使用指针。当您使用引用时,它会告诉您它不会为空(或者至少不应该是),并且当您想使用它时,您不需要检查myVector == 0
。
我对返回值应用相同的约定。例如对我这样的声明
vector<object>* MyClass::GetVector2()
表示该函数可能返回 nullptr/0,而
vector<object> & MyClass::GetVector2()
不能。
要安全地使用指针或引用,您必须确保MyClass
对象比MyOtherClass
对象寿命更长。在您的示例中,它很满意,因为 MyClass
对象是 MyOtherClass
的成员。
现在谈谈你的设计。如果可以通过GetVector()
函数访问MyClass::mVector
,为什么还要初始化引用?另外,你真的需要这样的访问吗?如果MyClass
能够维护与mVector
相关的所有内容会更好。
【讨论】:
人们总是告诉我要避免这样的指针,因为它们会导致意想不到的错误 问他们为什么。如果使用得当,它们不会导致意外的错误。 从来没有得到任何正确答案,为什么它们会导致错误,这就是为什么我现在很困惑 :) @slei 阅读 ***.com/questions/8706192/…以上是关于指针、参考还是智能指针?的主要内容,如果未能解决你的问题,请参考以下文章