views:

363

answers:

8

I have a factory that builds the objects with longest lifetime in my application. These have types, lets say, ClientA and ClientB, which depend on Provider (an abstract class with many possible implementations), so both clients have a reference to Provider as member.

According to the command-line arguments, the factory chooses one implementation of Provider, constructs it (with "new"), and passes it to the constructors of both clients.

The factory returns an object that represents my entire app. My main function is basically this:

int main(int argc, char** argv)
{
    AppFactory factory(argc, argv);
    App app = factory.buildApp();
    return app.run();
}

And the buildApp method is basically this:

App AppFactory::buildApp()
{
    Provider* provider = NULL;

    if (some condition)
    {
        provider = new ProviderX(); 
    }
    else
    {
        provider = new ProviderY();
    }

    ClientA clientA(*provider);
    ClientB clientB(*provider);

    App app(clientA, clientB);
    return app;
}

So, when execution ends, destructors of all objects are called, except for the provider object (because it was constructed with "new").

How can I improve this design to make sure that the destructor of the provider is called?

EDIT: To clarify, my intention is that both clients, the provider and the App object to share the same lifetime. After all answers, I now think both clients and the provider should be allocated on the heap its references passed to the App object, which will be responsible for deleting them when it dies. What do you say?

+2  A: 

make provider an instance variable of AppFactory. then make provider a smart pointer or delete it in AppFactory's dtor.

Ray Tayek
I think a relationshiop between Provider and Client is better than provider and appfactory...You are suggesting an arbitrary relationship that was not there before.
Tim
You are saying that the lifetime of the app is the scope of the factory. What if that changes later? really the scope is the life of the aggregated users of the provicer. In this case it is the clients...
Tim
I agree that the dependency shouldn't be on the factory -- what happens if the factory is use to create multiple instances of the app in different threads?
tvanfosson
I also think that the dependency shouldn't be on the factory, but the App object could own of the provider, as it already owns the other components.
seuvitor
A: 

Just call

delete provider;
provider = NULL;

in the destructor of ClientA and ClientB. This will also call the destructor of the provider.

Stefan
this doesn't account for the dtors getting called at different times. It also is not safe for mutli-threaded apps... better to have reference counting or something else.
Tim
Off topic: there is no value in setting a pointer to NULL after deleting it in a destructor.
Nemanja Trifunovic
Off topic: yes there is.
Marcin
@Marcin: Care to explain? Destructor is the very last thing that gets called in an object lifetime. After it gets executed, there is no valid object around.
Nemanja Trifunovic
If you use the pointer to the object in multiple classes which each tries to delete it, you have to set it to NULL after deleting it - otherwise the next class will try to delete already deallocated memory.
Stefan
+1  A: 

there's not really enough here to help much, but without changing too much you can add reference counting to the Provider object and when the clients get destructed they drop the reference. When the reference goes to 0 in the Provider object, then call delete this.

Your lifetimes and scope are a little sketchy. Why do you create some objects on the stack and some on the heap - specifically your clients?

Tim
Well, previously, all my objects used to live on the stack, but then I realized that my provider should have different implementations, and polymorphism and dynamic allocation entered the game..
seuvitor
+2  A: 

Unless App's constructor copies the Clients then they need to be new()ed as well - the current ones are allocated on the stack and will be deleted when app is returned.

I think you might want to be careful about which objects are being created - e.g. put debug statements in the Client's constructors.

What you probably want is to make Provider be reference counted, and have each Client just decrement the reference count, but that's a lot of work.

Alternatively make AppFactory own the Provider.

Douglas Leeder
You made a clearer point about what I was trying to say as well about the clients, and the code in general.
Tim
+1  A: 

An option would be to have the factory return an AppComponents object containing all the components that the factory constructs. I.e. something like this:

int main(int argc, char** argv)
{
    AppFactory factory(argc, argv);
    AppComponents components = factory.buildApp();
    return components.getApp().run();
}

The AppComponents class would then be responsible for deleting your Provider and other objects.

Rasmus Faber
can also just have a method called cleanup on the app that is called after run() returns.
Tim
The App object in my example has precisely this function of holding all the components. As you say, I should really make it responsible for deleting the provider. Thanks!
seuvitor
If your App-class does not currently have a direct dependency on the Provider-interface (just an indirect through the Client-class), you might not want to introduce one, just so that it can delete the Provider. Of course if you already have that dependency it should be fine to let App delete the ...
Rasmus Faber
.. provider. Just be careful not to violate the Single-Responsibility-Principle.
Rasmus Faber
For now, the App object has two responsibilities: holding all components AND running the main client (the App::run() method delegates to the main client). I will remove this delegation so that App has a single responsibility, as in your code snippet. Thanks Rasmus!
seuvitor
+1  A: 

Make provider a member variable of AppFactory, and delete it in destructor:

class AppFactory
{
    public:
    AppFactory(int argc, char** argv) : provider(NULL)
    {
       //...
    }
    ~AppFactory()
    {
        if (provider != NULL)
            delete provider;
    }
    App buildApp()
    {

        if (some condition)
        {
            provider = new ProviderX(); 
        }
        else
        {
            provider = new ProviderY();
        }

        ClientA clientA(*provider);
        ClientB clientB(*provider);

        App app(clientA, clientB);
        return app;

    } 
    private:
    Provider* provider;

};

int main(int argc, char** argv)
{
    AppFactory factory(argc, argv);
    App app = factory.buildApp();
    return app.run();
}
Igor Oks
rtayek said the same thing, but as pointed out in the comments there as well that is not a good idea. You've created a relationship where it didn't exist and doesn't need one. The relatiohsnip is with the provider and client.
Tim
If the relationship is only between the provider and the client, the provider can be deleted right after the deletion of the clients in buildApp().
Igor Oks
that is true. I don't think he intended it that way. I suspect that he wants those to live longer than that method, but again, we don't have all the information we need.
Tim
Good suggestion, but for me it makes more sense to make App own the provider, as suggested by Rasmus, thanks!
seuvitor
To clarify, my intention is that both clients, the provider and the App object have the same lifetime. After all answers, I now think they all should be allocated on the heap and deleted by the App object when its destructor is called. What do you say?
seuvitor
+2  A: 

It's very simple with a shared ownership smart pointer:

App AppFactory::buildApp()
{
    boost::shared_ptr<Provider> provider;

    if (some condition)
    {
        provider.reset(new ProviderX()); 
    }
    else
    {
        provider.reset(new ProviderY());
    }

    ClientA clientA(provider);
    ClientB clientB(provider);

    App app(clientA, clientB);
    return app;
}

Assuming the app object owns the clients, and the clients all share the one provider. Make the clients take a shared_ptr<Provider> then, instead of a Provider& . As long as there is still a copy of a shared_ptr owning the provider object, the object won't be freed.

The best would be to not copy clientA and clientB, and not copy app by returning it by value, but move the clients into the app, and move the app itself into the returned object. That will be possible with the upcoming C++ version. But currently, either you make them pointers (using shared_ptr), or you keep copying them. Another option would be to use auto_ptr, which has a pseudo-transfer-of-ownership semantic. But that template has some inherent problems. So you should avoid using it.

Johannes Schaub - litb
From the beginning, I though about using smart pointers to have Java-like memory management. Unfortunately, I can't use boost in this project. But thanks for pointing it out, I think this is the most elegant solution.
seuvitor
is it because you don't want the customers to have to download boost, or is it because you are not allowed to use it? if it is the former, you can also extract shared_ptr sources quite easily out of the boost tree with the "bcp" tool. i did it in the past and it works nicely. note it's all headers.
Johannes Schaub - litb
+1  A: 

You say "the provider and the App object to share the same lifetime" but beware that in in C++, the following code fragment ...

App app(clientA, clientB);
return app;

... is returning a copy of the App object: and therefore you may (depending on the compiler, see http://msdn.microsoft.com/en-us/library/ms364057(VS.80).aspx for example) actually have two App object instances (one inside the AppFactory::buildApp() method and another inside the main function).

To answer your question, I think I agree with your edit: pass the pointer-to-Provider into your App constructor, store it as member data of the App instance, and delete it when you destroy the App instance. As well as this, though, you might also change your code to ensure you don't copy the App instance: for example, allocate the App instance on the heap, change the AppFactory::buildApp() method to return a pointer to the App, and delete the App instance at the end of the main function.

ChrisW
Good point, I think this last approach where everything goes to the heap, including the App, will be good enough for me. Thanks Chris!
seuvitor