Ссылки на boost :: smart_ptr указывают на объект и проверяют его правильность - PullRequest
0 голосов
/ 29 июня 2011

Учитывая следующее:

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 будет содержать исходный Curve::Pointer, когда CurveShift понадобится, и, следовательно, curve_ может указывать на освобожденную память,или даже память, которая уже была перераспределена на что-то другое.Я считаю, что одним из возможных решений было бы CurveShift использовать boost:weak_ptr<Curve> вместо const Curve &, но я вполне уверен, что это означало бы, что вы больше не можете использовать Curve в стеке и в любом другом случаепридется идти в кучу (конструкторы становятся частными, а объекты создаются через фабрику).Есть ли лучшая стратегия для достижения желаемого поведения?Мне кажется, что хотя теоретически это может быть серьезной проблемой, случаи практического использования не могут привести к сложным ситуациям.

Ответы [ 2 ]

3 голосов
/ 29 июня 2011

Я заметил в ваших комментариях, что у вас есть объект, выделенный в стеке, который вы хотите std::shared_ptr, чтобы ... если это так, вам придется скопировать ваш объект из стека в кучу, делая что-тонапример:

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

Это затем выделит копию вашего стекового объекта в куче и создаст std::shared_ptr из этого выделенного в куче объекта.Затем вы можете скопировать только что созданный общий указатель в контейнер и т. Д.

Также я бы согласился с комментариями Немо о том, что ваш класс 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 экземпляру и увеличивает количество ссылок на указатель на кучу, которой он управляет.

2 голосов
/ 29 июня 2011

Если у вас есть shared_ptr, объект будет поддерживаться как действительный. Необработанная ссылка, конечно, не всегда будет действительной. Почему бы просто не сделать curve_ a shared_ptr? weak_ptr предназначен для разрыва циклов. Я не вижу здесь никаких циклов, поэтому для этого не должно быть никаких причин.

(я думаю, что здесь есть что-то, что ограничивает ваш дизайн, чего нет в вашем вопросе)

...