对 boost::smart_ptr 的引用指向对象并检查其有效性

发布于 2024-11-17 12:00:17 字数 928 浏览 2 评论 0原文

鉴于以下情况:

class Curve {
public:
  typedef boost::shared_ptr<Curve> Pointer;
  // ...
private:
  // ...
};

class CurveShift: public Curve {
public:
  CurveShift(const Curve & curve);
  // ...
private:
  const Curve & curve_;
  // ...
};

我想知道当您想做类似的事情时是否有一个共识的最佳实践可以使用:

Curve::Pointer pointer(new Curve());
SomeGlobalRepository::Add("key", pointer);

并且在其他地方您有:

CurveShift cs(*SomeGlobalRepository::Get("key"));

您确实没有任何保证 SomeGlobalRepository 会当 CurveShift 需要它时,包含原始的 Curve::Pointer,因此 curve_ 可能指向已释放的内存,甚至是已经重新分配的内存到别的东西。我相信一种可能的解决方案是 CurveShift 使用 boost:weak_ptr 而不是 const Curve &,但我我非常确定这意味着您不能再在堆栈上使用 Curve,并且任何实例都必须在堆上(构造函数变为私有,并且通过 工厂)。是否有更好的策略来实现所需的行为?我的直觉是,虽然理论上这可能是一个严重的问题,但实际用例不会造成这些棘手的情况。

Given the following:

class Curve {
public:
  typedef boost::shared_ptr<Curve> Pointer;
  // ...
private:
  // ...
};

class CurveShift: public Curve {
public:
  CurveShift(const Curve & curve);
  // ...
private:
  const Curve & curve_;
  // ...
};

I was wondering whether there is a consensus best practice to use when you want to do something like:

Curve::Pointer pointer(new Curve());
SomeGlobalRepository::Add("key", pointer);

And in some other place you have:

CurveShift cs(*SomeGlobalRepository::Get("key"));

You don't really have any assurance that SomeGlobalRepository will contain the original Curve::Pointer when CurveShift will need it, and hence curve_ might point to deallocated memory, or even memory that was already reallocated to something else. I believe that one possible solution would be for CurveShift to use a boost:weak_ptr<Curve> instead of a const Curve &, but I am pretty certain that would mean that you can't use Curve on the stack anymore, and any instance would have to go on the heap (with the constructors becoming private and the objects being created through a factory). Is there a better strategy to achieve the desired behavior? My gut feeling is that while in theory this could be a serious problem, practical use cases would not lend themselves to creating these tricky situations.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

别低头,皇冠会掉 2024-11-24 12:00:17

我在您的评论中注意到您在堆栈上分配了一个对象,您想要一个 std::shared_ptr 来...如果是这种情况,您将不得不从堆栈中复制您的对象然后,

std::shared_ptr<my_object_t> sh_ptr(new my_object_t(stack_object));

这将在堆上分配堆栈对象的副本,并从该堆分配的对象创建一个 std::shared_ptr 。然后,您可以将新创建​​的共享指针复制到容器等中。

另外,我同意 Nemo 的评论,即您应该让您的类 CurveShift 保存 shared_ptr 的副本,而不是比对 Curve 类对象的常量引用...这样,shared_ptr 对象将控制指针引用的生命周期,并且应该是容器或其他对象尝试销毁指向的内存由 shared_ptr 实例在其自身解构期间,内存引用仍将保留在 CurveShift 实例中,因为在其他地方调用 shared_ptr 的析构函数实际上不会释放堆上对象的内存,因为 CurveShift 实例对象具有对由shared_ptr。通过仅保留常量引用,您就消除了使用shared_ptr类型的全部优势,该类型通过某种形式的引用计数来控制在堆上分配的对象的解构。

最后,我会为您编写这样的类:

class CurveShift: public Curve {
public:
  CurveShift(const shared_ptr<Curve>& ptr): _curve(ptr)
  {
      // ... rest of constructor
  }

private:
  shared_ptr<Curve> curve_; //will remain valid for lifetime of CurveShift instance
  // ...
};

然后您将进行如下调用:

CurveShift cs(SomeGlobalRepository::Get("key"));

shared_ptr 复制到您的 CurveShift 实例,并将引用计数增加到其管理的堆上的指针。

I noticed in your comments that you have an object allocated on the stack that you want a std::shared_ptr to ... if that is the case, you'll have to copy your object from the stack into the heap doing something like:

std::shared_ptr<my_object_t> sh_ptr(new my_object_t(stack_object));

That will then allocate a copy of your stack-object on the heap and created a std::shared_ptr from that heap-allocated object. You can then copy your newly created shared pointer into a container, etc.

Also I would concur with Nemo's comments that you should have your class CurveShift hold a copy of the shared_ptr rather than a constant reference to a Curve class object ... that way the shared_ptr object will control the life-time of the pointer reference, and should a container or some other object try to destroy the memory pointed to by the shared_ptr instance during it's own deconstruction, the memory reference will still be maintained in the CurveShift instance since calling the destructor of the shared_ptr elsewhere will not actually deallocate the memory for the object on the heap as your CurveShift instance object has an active reference to that heap allocated object held by the shared_ptr. By holding just a constant reference, you remove the whole advantage of using a shared_ptr type which is controlled deconstruction of an object allocated on the heap through some form of reference-counting.

In the end, I would write you class like:

class CurveShift: public Curve {
public:
  CurveShift(const shared_ptr<Curve>& ptr): _curve(ptr)
  {
      // ... rest of constructor
  }

private:
  shared_ptr<Curve> curve_; //will remain valid for lifetime of CurveShift instance
  // ...
};

And then you would make a call like:

CurveShift cs(SomeGlobalRepository::Get("key"));

Which copies in the shared_ptr to your CurveShift instance and increases the reference count to the pointer on the heap its managing.

一枫情书 2024-11-24 12:00:17

如果您有一个shared_ptr,该对象将保持有效。当然,原始参考并不总是有效的。为什么不直接将 curve_ 设为 shared_ptr 呢? weak_ptr 旨在打破循环。我在这里没有看到任何循环,所以应该没有理由。

(我认为你的问题中缺少一些限制你的设计的东西)

If you have a shared_ptr, the object will be maintained as valid. The raw reference of course is not always going to be valid. Why not just make curve_ a shared_ptr? weak_ptr is designed to break cycles. I don't see any cycles here, so there should be no reason for it.

(I think there's something constraining your design here that's missing from your question)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文