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

发布于 2024-11-25 00:29:53 字数 212 浏览 3 评论 0原文

一个具体问题:

我有一个主应用程序,其中包含类型 A 和类型 B (以及其他类型)的对象。 B 类型的对象需要正确构造 A 对象(因此有一个构造函数 A(const B& b)。然而Main可能随时改变它所持有的B对象。我该如何制作 确定当 Main 更改其 B 对象时,A 对象的内部引用也会更改吗?

一般来说,管理对象生命周期有哪些好的做法,对象在哪里 有依赖性吗?

A concrete problem:

I have a Main application which has objects of type A and type B (among other types).
Object of type B requires A object to be properly constructed (so there is a constructor
A(const B& b). However Main may change B object it holds at any time. How do I make
sure that when Main changes its B object then the A object's internal reference is changed ?

In general, what are some good practices to manage object lifetimes, where objects
have dependencies ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

感情旳空白 2024-12-02 00:29:53

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

If A never caches any of B properties, and always references the instance of B it holds to generate any dependent output, any changes that are made to B should be reflected in subsequent calls to A. I am assuming you're simply storing a reference to B within the constructor and not creating a local copy.

生活了然无味 2024-12-02 00:29:53

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

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

If I understand correctly, you want to not just change the B object but completely replace it with a different B. References can't be changed once created, so you'll want to use pointers instead.

You may want to use the Observer Pattern to let the A objects know when their B should be replaced: http://en.wikipedia.org/wiki/Observer_pattern

澉约 2024-12-02 00:29:53

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

private:
  const B& theReference;

or 的内容(请记住在这种情况下还要更改您的构造函数)。

private:
  B& theReference;

因此,在您的代码中,如果您需要调用非常量方法,

In general: Always make sure you know about the ownership. Whenever you create an object, wither another object needs to be the owner or it has to be a local variable. In your case the main routine would be the owner of the instance to B. If you have a reference to B in your A instance, A will see all changes to the instance - just make sure you do not copy (not having a reference does implicit copying). So in your code you would have something like

private:
  const B& theReference;

or

private:
  B& theReference;

if you need to call non-const methods (remember to also change your constructor in that case).

满天都是小星星 2024-12-02 00:29:53

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

If I understood you correctly, if you make modifications to an object that main holds, it should in turn effect the object what A holds. For this you may take the help of constructor initializer.

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

Output :

10
20

一身骄傲 2024-12-02 00:29:53

请记住:

  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< /code> 将始终引用相同的 B 实例,在某些情况下,您可能只需要“通知”A B 中的属性已更改> 它引用的对象)。

Keep in mind:

  1. All problems can be solved with one more layer of indirection.
  2. Object ownership must be obvious.

In your case, if the B instance can come-and-go at any time (the old instance is deleted, a new one is "newed"), then you can create a "utility handle" class that "wraps" the B instance:

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

Then, your A class would reference a BHandle instance, or wholly contain a BHandle instance. Then, B instances can come-and-go, but A::my_b_handle_ would always reflect where the "current" B instance is.

On the other hand, if the B instance merely has data members that change (its instance itself does not come-and-go), then you don't need to do anything (A will always reference the same B instance, and you may in some cases merely need to "notify" A that properties changed in the B object it references).

腻橙味 2024-12-02 00:29:53

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

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. 对象之间的依赖关系(通过 int)
  3. 标识对象
  4. 依赖关系可以通过 int 或通过指针存储,
  5. 当生命周期结束时销毁对象

Here's how I handled the problem. User code looks like this:

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

This way every dependency is visible in the user code. The dependencies between objects are nicely stored inside a std::vectors in a Env class. Indexes to the vectors will be returned from the functions. create_A() and use_A() can communicate via ints. The objects will all be destroyed at the same time when Env class goes out of the scope. Your objects could be deriving from a base class which has virtual destructor.

If you have more than one int, recommended way is this:

struct ID { int i; };

Implementation of the interface would rely on the following functions:

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

The above approach solves the following problems with object lifetimes:

  1. lifetime of the objects
  2. dependencies between the objects (via ints)
  3. identifying the objects
  4. the dependencies could be stored either via int's or via pointers
  5. destroying the objects when lifetime ends
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文