C ++: Как управлять временем жизни и зависимостями объекта? - PullRequest
2 голосов
/ 18 июля 2011

Конкретная проблема:

У меня есть приложение Main, в котором есть объекты типа A и типа B (среди других типов).Объект типа B требует, чтобы объект был правильно сконструирован (поэтому существует конструктор A (const B & b). Однако Main может изменить объект B, который он содержит в любое время.Внутренняя ссылка на объект изменена?

В целом, каковы хорошие методы управления временем жизни объектов, когда объекты имеют зависимости?

Ответы [ 6 ]

3 голосов
/ 18 июля 2011

Если A никогда не кэширует какое-либо из B свойств и всегда ссылается на экземпляр B, который он содержит для генерации любого зависимого вывода, любые изменения, внесенные в B, должны отражаться в последующих вызовах A.Я предполагаю, что вы просто храните ссылку на B в конструкторе, а не создаете локальную копию.

1 голос
/ 18 июля 2011

Если я правильно понимаю, вы хотите не просто изменить объект B, но полностью заменить его другим B. Ссылки не могут быть изменены после создания, поэтому вместо них вы можете использовать указатели.

Возможно, вы захотите использовать Шаблон наблюдателя, чтобы сообщить объектам А, когда их Б следует заменить: http://en.wikipedia.org/wiki/Observer_pattern

0 голосов
/ 18 июля 2011

Вот как я справился с проблемой. Код пользователя выглядит так:

class Env
{
public:
   Env();
   ~Env();
private:
   void *priv;
};
class MyInterface
{
 public:
  MyInterface(Env &e) : e(e) { }
  int create_A();
  void use_A(int a);
 private:
   Env &e;
   void *priv; 
 };
 int main()
 { 
    Env e;
    MyInterface i(e);
    int a = i.create_A();
    use_A(a);
 }

Таким образом, каждая зависимость видна в коде пользователя. Зависимости между объектами хорошо хранятся в std :: vectors в классе Env. Индексы к векторам будут возвращены из функций. create_A () и use_A () могут общаться через int. Все объекты будут уничтожены одновременно, когда класс Env выйдет из области видимости. Ваши объекты могут быть производными от базового класса, в котором есть виртуальный деструктор.

Если у вас есть более одного int, рекомендуемый способ:

struct ID { int i; };

Реализация интерфейса будет опираться на следующие функции:

A *find_a(const Env &e, ID i);
ID create_a(Env &e, A *ptr);

Приведенный выше подход решает следующие проблемы с временем жизни объекта:

  1. время жизни объектов
  2. зависимости между объектами (через целые числа)
  3. идентификация объектов
  4. зависимости могут храниться либо через int, либо через указатели
  5. уничтожение объектов по окончании жизни
0 голосов
/ 18 июля 2011

Имейте в виду:

  1. Все проблемы можно решить с помощью еще одного слоя косвенности.
  2. Право собственности на объект должно быть очевидным.

В вашем случае, если экземпляр B может приходить и уходить в любое время (старый экземпляр удаляется, новый - "новый"), то вы можете создать класс "служебного дескриптора", который " оборачивает "экземпляр B:

class BHandle {
  B* b_; // can change at any time
  public:
    ....
};

Тогда ваш класс A будет ссылаться на экземпляр BHandle или полностью содержать экземпляр BHandle. Тогда B экземпляров могут приходить и уходить, но A::my_b_handle_ всегда будет отражать, где находится "текущий" B экземпляр.

С другой стороны, если экземпляр B просто имеет элементы данных, которые меняются (сам его экземпляр не приходит и не уходит), вам не нужно ничего делать (A всегда будет ссылаться на тот же экземпляр B, и в некоторых случаях вам может просто понадобиться «уведомить» A, что свойства изменились в B объекте, на который он ссылается).

0 голосов
/ 18 июля 2011

Если я вас правильно понял, если вы вносите изменения в объект, который хранится в main, это, в свою очередь, должно влиять на объект, который содержит A. Для этого вы можете воспользоваться помощью инициализатора конструктора.

#include <iostream>

class B{
    public:
        int num ;
        B(int arg):num(arg) {}
};

class A{
    public:
        const B& ref ;
        A( const B& arg ): ref(arg){}
};

int main()
{
        B objOne(10) ;
        A objTwo(objOne) ;

        std::cout << objTwo.ref.num << std::endl ;
        objOne.num = 20 ;
        std::cout << objTwo.ref.num << std::endl ;
}

Выход:

10
20

0 голосов
/ 18 июля 2011

В общем: всегда убедитесь, что вы знаете о праве собственности. Всякий раз, когда вы создаете объект, другой владелец должен быть владельцем объекта или локальной переменной. В вашем случае основная подпрограмма будет владельцем экземпляра B. Если в вашем экземпляре A есть ссылка на B, A увидит все изменения в экземпляре - просто убедитесь, что вы не копируете неявное копирование). Так что в вашем коде у вас будет что-то вроде

private:
  const B& theReference;

или

private:
  B& theReference;

если вам нужно вызывать неконстантные методы (не забудьте также изменить конструктор в этом случае).

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