【问题标题】:When to pass by pointer or shared_ptr何时通过指针或 shared_ptr 传递
【发布时间】:2016-07-17 21:46:12
【问题描述】:

关于通过引用或指针传递以及何时使用指针的问题有很多。

到目前为止我对该主题的理解是以下规则:

  • 总是尝试通过引用传递
  • 如果必须通过指针传递(仅使用指针)

在我的例子中,我必须使用指针来保留多态行为,因为我将传递的对象存储到向量中以供以后使用(这是一个“添加”方法)。
见:C++ Overridden method not getting called

我已阅读:

所以我的问题是:
如果我试图传递一个已包含在 shared_ptr 中的指针以添加到向量中,我应该

  • 传递对要添加到向量中的 shared_ptr 的引用(因为其他方法不实用)

  • 使用 shared_ptr::get 获取实际指针,传递该指针,使用 shared_ptr::reset 重新包装它,然后将其添加到向量中? (因为如果我要转移所有权,我应该只传递智能指针)

代码:

//method definition
void addToVector(shared_ptr<Object>& obj) {
    myVector.push_back(obj);
}
//call
shared_ptr<Object> myObj = make_shared<Object>();
addToVector(myObj);

//method definition
void addToVector(Object* obj) {
    shared_ptr<Object> toAdd;
    toAdd.reset(obj);
    myVector.push_back(toAdd);
}
//call
shared_ptr<Object> myObj = make_shared<Object>();
addToVector(myObj.get());

【问题讨论】:

  • 这取决于,你需要给我们指向对象的生命周期。
  • “始终尝试通过引用传递”的“规则”不是我想遵循的规则。通过引用传递本机数据类型(如 intdouble)没有意义,除非函数应该修改值。
  • @RichardCritten 指向的对象将持续到程序结束
  • 关于你的最后一个例子,这实际上很糟糕,会导致未定义的行为。你突然有两个不同的 std::shared_ptr 对象包装同一个指针,彼此不知道。如果一个上的引用计数器变为零,则内存被删除,但另一个共享指针对象仍然有一个指向(现在已删除)对象的指针。
  • @Yidna:不会有任何区别。你说过,对象一直持续到程序结束。如果这是真的,那么无论对象是否被向量引用,它都保持为真。所以使用shared_ptr 是没有意义的,因为shared_ptr 的全部目的是管理对象的生命周期,实际上您已经说过这些对象不需要管理它们的生命周期。

标签: c++ pointers vector reference shared-ptr


【解决方案1】:

当我将传递的对象存储到向量中以供以后使用时,我必须使用指针来保留多态行为

如果将指向对象存储在向量中,则不会保留多态行为

我应该...使用 shared_ptr::get 获取实际指针,传递该指针,使用 shared_ptr::reset 重新包装它,然后将其添加到向量中吗?

没有。共享指针可能不获取已由另一个共享指针拥有的指针的所有权。这将有未定义的行为。

(因为只有在转让所有权时我才应该传递智能指针)

如果您打算存储指向对象的共享指针,那么您正在 转让(共享)所有权。如果这是您的意图,则将 const 引用传递给共享指针,如链接答案中所述。

如果您不打算共享所有权,那么存储共享指针不是您应该做的。您可能想要存储引用包装器、裸指针或弱指针。您应该如何将引用传递给函数,将取决于您选择如何处理它。

【讨论】:

  • 将我原来的问题编辑为“存储”而不是“添加”以更好地反映我的意图。
  • @Yidna 不是在“复制”吗?无论如何,我改变了答案以反映这一点。
  • 是的,它曾经说“因为我正在复制传递的对象”,但这并不能准确反映我的意思,所以我将其更改为“存储传递的对象”,因为这允许对于是否复制值、复制引用或复制指针的歧义。
  • 我会接受这个答案,但我会补充一点,我最终使用了@JoachimPileborg 推荐的weak_ptr
  • @Yidna 我稍微扩展了答案,包括提到弱指针。
【解决方案2】:

第二个例子是未定义的行为,所以根本不能被认为是一种有效的方法:

void addToVector(Object* obj) {
    shared_ptr<Object> toAdd;
    toAdd.reset(obj); // n.b. could just use shared_ptr(obj) ctor
    myVector.push_back(toAdd);
}
shared_ptr<Object> myObj = make_shared<Object>();
addToVector(myObj.get()); // UB

发生的情况是 myObj 拥有它的所指对象,然后您使用 get() 形成指向该所指对象的原始指针,然后您在 addToVector() 中创建一个具有相同所指对象的新 shared_ptr。现在你有两个智能指针指向同一个对象,但是这两个智能指针不知道彼此,所以每个都会销毁对象,这是双释放的,这是未定义的行为。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-28
    • 2021-01-19
    • 1970-01-01
    • 1970-01-01
    • 2011-04-06
    • 1970-01-01
    • 1970-01-01
    • 2014-07-27
    相关资源
    最近更新 更多