Каков лучший указатель / ссылочный тип при возврате члена, возможно размещенного в стеке в C ++? - PullRequest
0 голосов
/ 31 января 2019

Итак, чтобы проиллюстрировать мой вопрос, я сделал пример:

#include <iostream>

using namespace std;


struct A
{
  void doSomething (){
      cout << "Something\n";
  }
};


struct B
{
  A a;

  A *getA ()
  {
    return &a;
  }
};


int
main ()
{

  B *b = new B ();
  A *a = b->getA ();


  // POINT 1
  if (nullptr != a)
    {
      a->doSomething ();
    }

  delete b;
  b = nullptr;

  // POINT 2
  if (nullptr != a)
    {
      a->doSomething ();
    }

  return 0;
}

Это компилируется и запускается без ошибок на моей машине, но если вы проверяете код, действительно существует проблема с висящим указателем настроки, следующие за комментарием с пометкой «POINT 2».

Так как b был удален, то a теперь недействителен (так как он был удален dtor из b).

Таким образом, я мог бы использовать общий указатель, чтобы исправить это, но это сохранило бы экземпляр a даже после удаления b, а также я не смог бы выделить a в стеке.Это две вещи, которые я хочу избежать.Вместо этого я просто хочу узнать, действителен ли a.

Я мог бы также использовать уникальный указатель, но тогда я мог бы иметь только один единственный экземпляр a, который тоже не тот, который я хочу, янужно много копий указателя на a.

Так есть ли какой-нибудь существующий тип указателя / ссылки, который позволил бы мне сделать это?Есть ли причина, почему это хорошая / плохая идея?

Ответы [ 3 ]

0 голосов
/ 31 января 2019

Единственное жизнеспособное решение с использованием стандартной библиотеки, которое приходит на ум, - это использовать std :: weak_ptr () - это позволит проверить достоверность объекта, не владея его владением.Это связано с ценой - вы должны сохранить право собственности на нее с std::shared_ptr.Хотя можно создать std::shared_ptr для объекта с автоматической продолжительностью хранения и удалением noop, я бы сделал это только в том случае, если мне действительно нужно это, поскольку такой метод подвержен ошибкам и побеждает цель умного указателя.

0 голосов
/ 31 января 2019

Лучший способ - не выставлять a.

Ваш B - это интерфейс.Дайте ему функции, которые вам нужно выполнить.Пусть он продолжит вызывать все, что ему нужно, на a, чтобы это произошло.

Затем удалите getA() и сделайте a приватным.

Теперь этополностью инкапсулирован, и вызывающая область не может обойти его таким образом!

Нет необходимости в указателях или динамическом выделении;просто хороший старомодный ООП.

0 голосов
/ 31 января 2019

Вы только что обнаружили чудеса семантики владения:)

Как решить эту проблему, зависит от дизайна вашего приложения: что вам нужно и чего вы пытаетесь достичь.

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

Однако, обратите внимание, что (ab) используяобщие указатели могут быть признаком плохого дизайна.


Кстати, ваш A a; член не размещен в стеке (т. е. заголовок неверен).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...