开发者

References to boost::smart_ptr pointed to object and checking their validity

开发者 https://www.devze.com 2023-03-15 20:55 出处:网络
Given the following: class Curve { public: typedef boost::shared_ptr<Curve> Pointer; // ... private:

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 ach开发者_运维百科ieve 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.


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.


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)

0

精彩评论

暂无评论...
验证码 换一张
取 消