Простая ссылка вместо weak_ptr, чтобы сломать круговую зависимость
Взглянув на std::weak_ptr
Я видел в нескольких местах, что он может быть использован для устранения утечек памяти из-за циклических зависимостей с помощью std::shared_ptr
, См., Например, эти два принятых ответа: [1], [2].
Принимая последний ссылочный ответ, предлагаем исправление:
#include <memory>
#include <iostream>
struct B;
struct A {
std::shared_ptr<B> b;
~A() { std::cout << "~A()\n"; }
};
struct B {
std::weak_ptr<A> a;
~B() { std::cout << "~B()\n"; }
};
void useAnB() {
auto a = std::make_shared<A>();
auto b = std::make_shared<B>();
a->b = b;
b->a = a;
}
int main() {
useAnB();
std::cout << "Finished using A and B\n";
}
Это похоже на излишество, но почему бы просто не использовать ссылку? Я понимаю, что в этом примере b->a
не установлен в конструкторе, так что ссылка не будет действительно сокращать его, поэтому мой вопрос:
Есть ли причина использовать
std::weak_ptr
вместо ссылки, если целью является нарушение циклической зависимости, если мы можем установить ее в конструкторе?
ПРИМЕЧАНИЕ: я понимаю полезность std::weak_ptr
держать ссылку, которая может быть признана недействительной. Мой вопрос касается только полезности, когда целью является исключительно нарушение круговой зависимости.
3 ответа
Вы не можете проверить, ссылается ли ссылка (или простой указатель) на существующий объект, и вы не можете "переустановить" ссылку, например, в назначении.
Вот немного измененная функция:
void useAnB() {
std::shared_ptr<B> oops;
{
auto a = std::make_shared<A>();
auto b = std::make_shared<B>();
a->b = b;
b->a = a;
oops = b;
}
// use oops->a
}
Как ты мог знать, что oops->a
больше не ссылается на действительный объект, если это был простой указатель или ссылка?
Я понимаю полезность
std::weak_ptr
держать ссылку, которая может быть признана недействительной. Мой вопрос касается только полезности, когда целью является исключительно нарушение круговой зависимости.
Хорошо, если у вас есть круговая зависимость (или даже если у вас ее нет), и вы хотите сохранить ссылку на "главный" объект где-то еще, чтобы вы могли получить к нему доступ, и вы точно знаете, что этот объект не собирается чтобы уйти, пока вы, возможно, захотите это сделать, тогда да, я бы просто использовал ссылку, потому что:
- это дешевле
- это может избежать необходимости превращать главный объект в
shared_ptr
в первую очередь (а они сами по себе довольно дорогие)
В конце концов, все сводится к выбору ваших объектов для наилучшего выполнения любой работы, в которой вы нуждаетесь. Конечно, std::weak_ptr
это не ответ на каждую девичью молитву.