Сейчас я пытаюсь научиться использовать умные указатели. Однако при проведении некоторых экспериментов я обнаружил следующую ситуацию, для которой не смог найти удовлетворительного решения:
Представьте, что у вас есть объект класса A, являющийся родительским для объекта класса B (дочерний), но оба должны знать друг друга:
class A;
class B;
class A
{
public:
void addChild(std::shared_ptr<B> child)
{
children->push_back(child);
// How to do pass the pointer correctly?
// child->setParent(this); // wrong
// ^^^^
}
private:
std::list<std::shared_ptr<B>> children;
};
class B
{
public:
setParent(std::shared_ptr<A> parent)
{
this->parent = parent;
};
private:
std::shared_ptr<A> parent;
};
Вопрос в том, как объект класса A может передать a std::shared_ptr
самого себя ( this
) своему потомку?
Существуют решения для общих указателей Boost ( получение boost::shared_ptr
forthis
), но как с этим справиться с помощью std::
интеллектуальных указателей?
Ответы:
Есть как
std::enable_shared_from_this
раз для этого. Вы наследуете его и можете вызывать.shared_from_this()
изнутри класса. Кроме того, вы создаете здесь циклические зависимости, которые могут привести к утечкам ресурсов. Это можно решить с помощьюstd::weak_ptr
. Итак, ваш код может выглядеть так (при условии, что дети полагаются на существование родителя, а не наоборот):Однако обратите внимание, что для вызова
.shared_from_this()
требуется, чтобыthis
он принадлежал пользователюstd::shared_ptr
в момент вызова. Это означает, что вы больше не можете создавать такой объект в стеке и, как правило, не можете вызывать.shared_from_this()
из конструктора или деструктора.источник
shared_ptr
основе конструкции по умолчаниюshared_ptr
и на что бы вы ниshared_ptr
не имеют отношения к этому вопросу.shared_from_this
В предварительных условиях четко указано, что объект должен принадлежать (а не простоshared_ptr
указываться ) кем-то в момент вызова.shared_ptr
требуется в момент вызова, но в типичном шаблоне использования, то есть чем-то вродеshared_ptr<Foo> p(new Foo());
,shared_ptr
предполагает владение объектом только после того, как он полностью построен. Это можно обойти, создавshared_ptr
конструктор, инициализированный с помощью,this
и сохранив его где-то нелокально (например, в ссылочном аргументе), чтобы он не умер после завершения конструктора. Но такой запутанный сценарий вряд ли понадобится.У вас есть несколько проблем в дизайне, которые, похоже, связаны с неправильным пониманием интеллектуальных указателей.
Умные указатели используются для объявления права собственности. Вы нарушаете это, заявляя, что оба родителя владеют всеми дочерними элементами, но также что каждый ребенок владеет своим родителем. Оба не могут быть правдой.
Кроме того, вы возвращаете слабый указатель в
getChild()
. Тем самым вы заявляете, что вызывающий абонент не должен заботиться о праве собственности. Теперь это может быть очень ограничивающим, но также при этом вы должны убедиться, что рассматриваемый дочерний элемент не будет уничтожен, пока все еще сохраняются какие-либо слабые указатели, если вы будете использовать интеллектуальный указатель, он будет отсортирован сам .И последнее. Обычно, когда вы принимаете новые объекты, вы должны принимать необработанные указатели. Умный указатель может иметь собственное значение для обмена дочерними элементами между родителями, но для общего использования вы должны принимать необработанные указатели.
источник