shared_ptr
решает проблемы управления памятью, как регулярные выражения решают проблемы синтаксического анализа html.
shared_ptr
может быть частью решения проблемы управления жизненным циклом, но это никоим образом не является формой или формой, которую можно использовать случайно.Очень легко иметь «неуместные» указатели или циклы ссылок с shared_ptr
. По моему опыту, используйте shared_ptr
как внутреннюю частную деталь реализации с охранниками, инвариантами и аксиомами, которые вместе доказывают, что вы не можете сформировать циклы, и у вас есть неплохие шансы на отсутствие проблем.
Более половины моего использования shared_ptr
состоит из одного места, которое «владеет» указателем, и других наблюдателей, у которых есть weak_ptr
, за исключением узких окон, когда они проверяют, что ресурс все еще существует, а также причина полагать, что shared_ptr
не умрет в этом узком окне.
Еще один хороший способ использования - когда у меня ситуация с копированием на запись, где у меня есть состояние неизменного объекта, которое можно скопировать (хранится в shared_ptr<const T> pimpl
. Когда происходит операция записи, если я ' м только один пользователя я бросил, что к shared_ptr<T>
и изменить его. в противном случае, я копирую его в shared_ptr<T>
и изменить его. Затем я храню его обратно как shared_ptr<const T>
в обеих случаях.
Просто рассеяние shared_ptr
s вокруг в моем опыте неизбежно приводит к утечкам и ресурсам, продолжающимся намного дольше, чем они должны.
С другой стороны, вы должны просто использовать unique_ptr
. make_unique
и unique_ptr
должны заменить new
и delete
в вашем коде практически при любых обстоятельствах. На самом деле очень сложно получить unique_ptr
, и, когда вы это делаете, обычно это связано с тем, что у старого кода был серьезный риск утечки или вы не понимали, каким образом этот ресурс управлялся раньше.
В новом коде это без проблем. В старом кодексе, если вам нужно понять время жизни объектов, вам нужно будет учиться достаточно, чтобы в полной мере разместить право собственности на unique_ptr
. Большим исключением является то, что вы выполняете программирование «культового груза» (модифицируя сложную систему, которую вы не понимаете способами, похожими на другой код в системе, и надеетесь, что она будет работать, потому что другой код работал) не является возможно управлять таким ресурсом. Существуют также некоторые другие исключения, такие как объекты, которые управляют своей собственной жизнью сложным способом.
Управление ресурсами, не связанными с new
, с unique_ptr
является более сложным, но я также считаю, что стоит.
И иногда вы вынуждены .release
указатель на длинный C-стиль void*
заполненный звонок.
Существует также время выполнения накладных расходы на shared_ptr
, но концептуальные накладные расходы shared_ptr
делает объект жизнь гораздо труднее понять, реальная причина, чтобы избежать его использования.
shared_ptr
может использоваться, чтобы сделать модные вещи, но не решает проблему, это инструмент, который в рамках комплексной системы управления ресурсами вы можете использовать, чтобы сделать ваше решение немного проще.
На имеется почти нулевой промежуток времени выполнения: он имеет тот же размер, что и указатель, и он просто вызывает delete
в конце жизненного цикла.
unique_ptr
решает проблемы, связанные с управлением ресурсами, мертвыми на их пути. Они испаряются после правильного использования.
В вашем конкретном примере, я бы либо поместить unique_ptr
с в tree
, и сохранить сырые указатели в узлах.
В качестве альтернативы, сохраните unique_ptr
с в векторе children
и необработанных указателях в дереве и в указателе родителя.
В любом случае, все операции, которые добавляют/удалять узлы должны пройти через tree
(принимая аргумент для узла мишени), как состояние tree
и в node
, необходимые, чтобы быть в синхронизации.
Вы выразили заинтересованность в получении случайный узел, когда я указал, что список узлов в корне tree
была плохая идея.
Просто сохраните количество детей в каждом узле. (Это требует работы при добавлении/изменении/удалении дочерних элементов, которые должны каскадироваться до корня).
Добавить:
node* node::nth_node(int n) {
if (n == 0) return this;
--n;
for(auto&& child:children) {
if (n < child->subtree_size)
return child->nth_node(n);
n -= child->subtree_size;
}
return nullptr; // n is too big
}
это становится п-й потомка узла, предполагая subtree_size
, насколько велика дерево node
является корнем (в том числе и себя, поэтому он никогда не должен быть 0
).
Чтобы получить случайный узел из tree
, создайте случайное число от 0
до root->subtree_size
. Т.е., если root->subtree_size
составляет 3
, ваше случайное число: 0
, 1
или 2
.
Затем позвоните по номеру root->nth_node(that_random_number)
.
Кому принадлежат объекты 'node'? Семантика собственности обычно определяет тип используемого указателя. –
Я редактировал. Дереву принадлежит это – user3191398