9

I'm coming from C# and trying to translate some of my practices into C++. I've used dependency injection in various places throughout my code using raw pointers. Then I decide to replace the raw pointers with std::shared_ptr's. As part of that process it was suggested that I consider using stack allocated automatic variables rather than dynamically allocating them (see this question although that question was in the context of unique_ptr so maybe that is different).

I believe the below example shows the use of automatic variables.

class MyClass
{ 
public:
   MyClass(ApplicationService& app): appService_(app)
   {
   }

   ~MyClass()
   {
        appService_.Destroy(something);

   }
private:   
   ApplicationService& appService_;
}

class ConsumerClass
{
    DoSomething()
    {
        CustomApplicationService customAppService;
        MyClass myclass(customAppService);
        myclass...
    }
}

In the above example, when customAppservice and myclass go out of scope how do I know which will be destroyed first? If customAppService is destroyed first than the MyClass destructor will fail. Is this a good reason to use shared_ptr instead in this scenario or is there a clean way around this?

UPDATE

ApplicationService is a class that is a wrapper around global functions needed to interact with a 3rd party library that my code uses. I have this class as I believe it's the standard way to support unit testing and stubbing/mocking of free standing functions. This class simply delegates calls to the corresponding global functions. The call appService_.Destroy(something); is actually destroying an object used by each specific instance of MyClass not destroying anything do with the Application class itself.

Community
  • 1
  • 1
User
  • 62,498
  • 72
  • 186
  • 247

2 Answers2

7

The answer is: you don't need to know, as your design is broken, anyway.

First, a Destroy sounds like a bad idea, furthermore if called in an object that is not responsible for the destruction of the other object. The code from the Destroy method belongs into ApplicationService's destructor (which is hopefully virtual, although in this case it doesn't actually need to), which in contrast to C# gets called at a perfectly determined point in time.

Once you've done this, you will (hopefully) realize, that it is not the responsibility of MyClass to destroy the appService_, as it does not own it. It is the responsibility of the ConsumerClass (or rather the DoSomething method), which really manages the actual service and which does actually destroy it automatically once you've moved Destroy's code into the destructor. Isn't it nice how RAII does make happen everything in a clean and automatic way?

class MyClass
{ 
public:
   MyClass(ApplicationService& app): appService_(app)
   {
   }

private:   
   ApplicationService& appService_;
}

class ConsumerClass
{
    DoSomething()
    {
        CustomApplicationService customAppService;
        MyClass myclass(customAppService);
        myclass...
    }
}

class ApplicationService
{
public:
    virtual ~ApplicationService()
    {
        //code from former Destroy method
    }
}

class CustomApplicationService
{
public:
    virtual ~CustomApplicationService()
    {
        //code from former Destroy method
    }
}

This is IMHO the perfect clean C++ way around it and the problem is definitely not a reason to spam shared_ptrs. Even if you really need a dedicated Destroy method and cannot move the code into the destructor (which I would take as a motivation for overthinking the design), then you would still call Destroy from DoSomething as again, MyClass is not responsible for destroying the appService_.

EDIT: According to you update (and my stupid overlooking of the something argument), your design seems indeed quite correct (at least if you cannot mess with changing the ApplicationService), sorry.

Allthough class members should get destroyed in reverse order of construction, I'm not sure this also holds for local automatic variables. What you could do to make sure the destructors get called in a defined order is introduce nested scopes using simple blocks:

void DoSomething()
{
    CustomApplicationService customAppService;
    {
        MyClass myclass(customAppService);
        myclass...
    }       // myclass destroyed
}       // customAppService destroyed

Of course there is still completely no need to use dynamic allocation, let aside shared_ptrs. Although the nested blocks blow the code a bit, it is nothing against the ugliness of dynamic allocation applied in a non-dynamic way and without reason and it at least "looks nice in a semantic way" with customAppService's declaration on top of the block ;)

Christian Rau
  • 45,360
  • 10
  • 108
  • 185
  • I know it wasn't self-evident from my example but MyClass is not destroying appService_. See my update. – User Nov 01 '11 at 23:24
  • @User Ah sorry, me stupid ovrlooked that `something` argument. – Christian Rau Nov 01 '11 at 23:26
  • No worries you don't have the the full context. I trust that technically works but I'm wondering about maintenance & the possibility of creating brittle code & whether the code communicates the intent. I think I'd rather use a shared_ptr than rely on non-obvious destruction behavior. It reminds me of the ordering of dependent items in constructor initialization lists (how objects get initialized in the same order they are declared). When I read people talking about relying on that fact it seems really brittle IMHO. But if this is the best way then I will consider doing this. – User Nov 01 '11 at 23:54
  • @User With the explicit blocks you can be perfectly sure and it doesn't use any "brittle" information (I hope my intuition guessed the correct meaning of brittle). And I regard the knowledge that class members get constructed in the order of declaration (the order they appear in the header file, if you want) and not the order they appear in initializer lists as standard knowledge. It would be like if you didn't know the difference between `C++` and `++C`. There is completely no need to use `shared_ptr`s here. Either you code in C++ or in C#, but please don't code in C++/C#. – Christian Rau Nov 02 '11 at 00:00
  • 1
    @User Don't let laziness drive you to ignoring all memory and resource considerations and spamming `shared_ptr`s all over the place (sorry if that sounds a bit harsh). Explicit (and deterministic!) memory (and even more important, general ressource) management is one of the key strengths of C++ and enables such beautiful things like RAII and easy exception safety. – Christian Rau Nov 02 '11 at 00:03
  • Fair enough. As I continue to learn about this I imagine it will become clearer. I'm reading http://www.parashift.com/c++-faq-lite/value-vs-ref-semantics.html now. – User Nov 02 '11 at 00:47
  • Thanks for guiding me on the C++-way of things. It's strange coming from C# to use stack allocated variables everywhere. I have changed much of my code from using shared_ptr to using stack allocated class member objects and dependency injecting them as references. – User Nov 03 '11 at 00:43
2

In C++, objects, in general, are destroyed in the order that is exact opposite of the order they were created in.

Based on your example, MyClass will be destroyed before CustomApplicationService

The exception is when a destructor is called explicitly. However, I don't think you should concern yourself with this exception at this stage.

Another subtlety is called static initialization order fiasco . However, this does not apply to automatic (stack) variables.

Edit:
From C++2003 - looked for 'reverse order'

6.6.0.2

On exit from a scope (however accomplished), destructors (12.4) are called for all 
constructed objects with automatic storage duration (3.7.2) (named objects or 
temporaries) that are declared in that scope, in the reverse order of their
declaration. ... [Note: However, the program can be terminated (by calling exit()
or abort()(18.3), for example) without destroying class objects with automatic
storage duration. ]
Chris Bednarski
  • 3,364
  • 25
  • 33
  • It's the sub objects of a particular instance destructed in reverse order. Are you sure it is still the reverse in this scenario too ? Any citation would be helpful. – Mahesh Nov 01 '11 at 22:56
  • Absolutely. If MyClass contains sub objects, they will get destroyed completely before CustomApplicationService destructor is called. – Chris Bednarski Nov 01 '11 at 22:58
  • I believe Chris is correct, but if I really wanted to be sure (and not trust interpretations of specs) I would put the MyClass object into its own scope with { MyClass myClass(...); ... } and then I know the object goes away first. – drdwilcox Nov 01 '11 at 23:00
  • Actually a standard proof of this statement would be nice. I know it holds for member variables, but also for local variables? – Christian Rau Nov 01 '11 at 23:36
  • 1
    This C++ FAQ says this is correct: http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.2 although it doesn't reference a spec. – User Nov 02 '11 at 00:30
  • +1 For the standard quote. I think he got his answer and can freely use his code. – Christian Rau Nov 02 '11 at 15:48