开发者

C++: How to manage object lifetimes and dependencies?

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 obje开发者_StackOverflowcts have dependencies ?


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.


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


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).


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


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).


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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜