Простая ссылка вместо weak_ptr, чтобы разорвать круговую зависимость - PullRequest
0 голосов
/ 03 июля 2018

Взглянув на 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 ]

0 голосов
/ 03 июля 2018

Вы не можете проверить, ссылается ли ссылка (или простой указатель) на существующий объект, и вы не можете "переустановить" ссылку, например, в присваивании.

0 голосов
/ 11 июля 2018

Я понимаю полезность std::weak_ptr для хранения ссылки, которая может быть признана недействительной. Мой вопрос касается только полезности, когда цель состоит исключительно в том, чтобы разорвать круговую зависимость.

Хорошо, если у вас есть круговая зависимость (или даже если у вас ее нет), и вы хотите сохранить ссылку на «главный» объект где-то еще, чтобы вы могли получить к нему доступ, и вы точно знаете, что этот объект не собирается уходить, пока вы, возможно, захотите это сделать, тогда да, я бы просто использовал ссылку, потому что:

  • дешевле
  • это может избежать необходимости сделать главный объект shared_ptr во-первых (а это само по себе довольно дорого)

В конце концов, все сводится к выбору ваших объектов для наилучшего выполнения любой работы, в которой вы нуждаетесь. Конечно, std::weak_ptr не является ответом на молитву каждой девы.

0 голосов
/ 03 июля 2018

Вот немного измененная функция:

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 больше не ссылается на действительный объект, если это был простой указатель или ссылка?

...