【问题标题】:C++: How to manage object lifetimes and dependencies?C++:如何管理对象生命周期和依赖关系?
【发布时间】:2011-07-18 15:46:20
【问题描述】:

一个具体的问题:

我有一个主应用程序,它具有 A 类型和 B 类型(以及其他类型)的对象。 B类型的对象需要正确构造一个对象(所以有一个构造函数 A(常量 B&b)。但是 Main 可以随时更改它持有的 B 对象。我该怎么做 确定当 Main 更改其 B 对象时,A 对象的内部引用也会更改?

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

【问题讨论】:

  • 如果 B 需要正确构造 A,你不是说有 B(const A& a) 构造函数吗?
  • 更改是指对其成员的修改?
  • @MadKeithV:是的 - 我的意思是 B(const A& a) 构造函数。

标签: c++ dependencies object-lifetime


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    如果我理解正确,您不仅要更改 B 对象,还要用不同的 B 完全替换它。引用一旦创建就无法更改,因此您需要改用指针。

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

    【讨论】:

      【解决方案3】:

      一般而言:始终确保您了解所有权。每当您创建一个对象时,另一个对象必须是所有者,或者它必须是局部变量。在您的情况下,主例程将是 B 实例的所有者。如果您在 A 实例中有对 B 的引用,A 将看到对实例的所有更改 - 只要确保您不复制(没有引用确实隐式复制)。所以在你的代码中你会有类似的东西

      private:
        const B& theReference;
      

      private:
        B& theReference;
      

      如果您需要调用非常量方法(请记住在这种情况下也要更改您的构造函数)。

      【讨论】:

        【解决方案4】:

        如果我理解正确,如果你对 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

        【讨论】:

          【解决方案5】:

          记住:

          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 它引用的@​​987654334@ 对象中的属性发生了变化。

          【讨论】:

            【解决方案6】:

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

            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() 可以通过整数进行通信。当 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. 在生命周期结束时销毁对象

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2011-04-07
              • 1970-01-01
              • 2012-11-06
              • 2012-12-28
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多