我有一个引用,想调用一个需要 boost::shared_ptr 的函数

I have a reference and want to call a function that takes boost::shared_ptr

本文关键字:boost shared 函数 ptr 一个 引用 有一个 调用      更新时间:2023-10-16

我有一个对对象的引用,并且想调用一个函数来获取该对象的boost::shared_ptr。如果我构建一个 boost::shared_ptr 来调用我的 boost::shared_ptr 从堆栈中取消,那么对象也会被取消!这正是我运行此代码时发生的情况:

double f(boost::shared_ptr<Obj>& object)
{
  ...
}
double g(Obj& object)
{
  boost::shared_ptr<Obj> p(&object);
  double x = f(p);
  ...
}

有没有办法让它工作?如何在 g(( 中创建一个 boost::shared 指针,让我的对象在最后保持活动状态?我想我必须将其连接到已经指向对象的其他共享指针的引用计数机制......但是怎么做呢?

即使我让它工作,你认为这种方式是糟糕的设计吗?解决此类问题的最佳实践是什么?在我的代码中,我有同时使用共享指针和引用的对象和方法,我不能只处理这些或那些......

一个接受shared_ptr的函数正在说明它的作用。它说,"我想潜在地声称这个对象的共享所有权"。如果这不是真的,那么它是一个写得不好的函数,根本不应该shared_ptr

通过对对象的非const引用来获取值的函数意味着该函数可以修改对象,但不能声明所有权。如果你不拥有某样东西,你也不能把所有权交给别人。

现在,您可以执行使用空删除器函数的技巧:

void EmptyDeleter(Obj *) {}
double g(Obj& object)
{
  boost::shared_ptr<Obj> p(&object, EmptyDeleter);
  double x = f(p);
  ...
}

但是,您现在正在对f撒谎.它不拥有object;它不能拥有object.object很可能是一个堆栈对象,f完成后随时可能消失。如果f是类的成员,则它可能会将shared_ptr存储在成员变量中。此时,它将对死物体进行shared_ptr。这正是shared_ptr旨在防止的事情。

正确的答案是,f不按shared_ptr取其参数(如果可修改,则使用非const引用或非const指针,如果不可修改,则使用const&(,或者g通过shared_ptr获取其参数。

您可以创建一个实际上不会释放对象的shared_ptr。喜欢这个:

struct FictiveDisposer {
    template <class T> void operator ()(T) {}
};
Obj& object = /* ... */;
boost::shared_ptr<Obj> myPtr(&obj, FictiveDisposer ());
// you may use myPtr

但是,您应该谨慎使用它。如果您确定要调用的函数不会尝试"保存"您的对象以供以后使用 - 没有问题。否则,您必须保证对象的已保存shared_ptr的生存期不会超过对象的实际生存期。

简单来说:你得到了对对象的引用。它不是您创建的,您可能不会影响其生命周期(shared_ptr也不能(。因此,可能会出现对象不再存在的情况,它仍然被shared_ptr引用。必须避免这种情况。

你必须考虑 f(( 的目的。据推测,如果它需要shared_ptr,f 打算随着时间的推移保留此指针的共享所有权,超过其返回。为什么?当你给它传递一个shared_ptr时,f(( 假设什么?一旦你回答了这个问题,你就能弄清楚如何编码g((。

如果由于某种原因 f(( 不需要保留指针的共享所有权,那么如果你可以控制它的接口,它可以重写为 Obj* 或 Obj& 而不是shared_ptr。然后,任何拥有shared_ptr的代码都可以通过将指针从shared_ptr中拉出或取消引用来调用 f。

这通常是库界面设计不佳的标志。 shared_ptr(但也有例外(。 由于功能你是呼叫期望承担责任,或至少部分承担责任责任,对于您传递的对象以及代码的其余部分没有为此做好准备,您唯一安全的解决方案是克隆对象,例如:

double x = f( boost::shared_ptr<Obj>( new Obj( object ) ) );

但你最好找出为什么f需要 shared_ptr,以及为什么g不能把一个作为论据。

如何在 g(( 中创建一个 boost::shared 指针,让我的对象在最后保持活动状态?

您可以为共享指针提供一个不执行任何操作的自定义析构函数:

boost::shared_ptr<Obj> p(&object, [](void*){});

或者,如果您的编译器不支持 lambda:

void do_nothing(void*) {}
boost::shared_ptr<Obj> p(&object, do_nothing);

即使我让它工作,你认为这种方式是糟糕的设计吗?

是的

:您将失去共享指针为您提供的生存期管理,现在您的责任是确保对象比所有共享指针的寿命更长。

解决此类问题的最佳实践是什么?

确定您正在使用的所有对象的所有权模型,并坚持下去。当您想要共享所有权时,共享指针可能很有用,但在其他方面则不然。在你的情况下,f想要分享所有权,而g似乎想要独家所有权;最好考虑一下他们为什么想要这样做,以及您是否可以更改一个以与另一个兼容。

std::shared_ptr<T>是可以赋予多个实体引用对象的所有权。如果接口需要std::shared_ptr<T>则有两种可能性:

  1. 有人在接口中无知地使用 std::shared_ptr<T>,该接口旨在接收T对象或引用或指向T对象的指针。如果是这种情况,作者应接受教育(如果这不起作用,则应从他目前的职责中解脱出来从事新的职业(并更正界面。
  2. 由于现在所有使用 std::shared_ptr<T> 的接口都使用它来可能向对象授予共享所有权,因此很明显,分配给T的堆栈不是此类接口的合适参数。唯一可能的参数是一个T对象,其生命周期通过std::shared_ptr<T>
  3. 保持。

我意识到这并不能回答最初的问题,但应该清楚的是,唯一可行的做法是:永远不要尝试将对象传递给一个函数,该函数采用无法完全由此类指针控制的std::shared_ptr<T>!(这同样适用于共享指针的boost版本(。