C ++:如何管理对象的生命周期和依赖关系?

时间:2011-07-18 15:46:20

标签: c++ dependencies object-lifetime

具体问题:

我有一个Main应用程序,它包含A类和B类(以及其他类型)的对象。 类型B的对象需要正确构造一个对象(因此有一个构造函数 A(const B& b)。但是Main可以随时更改它保存的B对象。我该怎么做 确保当Main更改其B对象时,A对象的内部引用会更改吗?

一般来说,管理对象生命周期的一些好方法是什么? 有依赖吗?

6 个答案:

答案 0 :(得分:3)

如果A从不缓存任何B属性,并且始终引用B的实例,则生成任何相关输出,对B所做的任何更改应该反映在随后的A调用中。我假设您只是在构造函数中存储对B的引用而不是创建本地副本。

答案 1 :(得分:1)

如果我理解正确,你不仅要改变B对象,而且要用不同的B替换它。一旦创建,就不能改变引用,所以你需要使用指针。

您可能希望使用观察者模式让A对象知道何时应该替换他们的B:http://en.wikipedia.org/wiki/Observer_pattern

答案 2 :(得分:0)

一般情况下:始终确保您了解所有权。无论何时创建对象,另一个对象都需要是所有者,或者它必须是局部变量。在你的情况下,主例程将是B实例的所有者。如果你在A实例中有对B的引用,A将看到对实例的所有更改 - 只是确保你不复制(没有引用吗?隐式复制)。因此,在您的代码中,您将拥有类似

的内容
private:
  const B& theReference;

private:
  B& theReference;

如果你需要调用非const方法(在这种情况下还记得改变你的构造函数)。

答案 3 :(得分:0)

如果我理解正确,如果你对主要持有的对象进行修改,它应该反过来影响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

答案 4 :(得分:0)

请记住:

  1. 所有问题都可以通过一层间接来解决。
  2. 对象所有权必须明显。
  3. 在您的情况下,如果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对象中更改的属性。

答案 5 :(得分:0)

以下是我处理问题的方法。用户代码如下所示:

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);
 }

这样,每个依赖项都在用户代码中可见。对象之间的依赖关系很好地存储在Env类的std :: vectors中。将从函数返回向量的索引。 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. 在终身结束时销毁对象