Unity Dependency Injection in an Initialiser List

This topic is 3382 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

I have a situation where there are RAII wrapper components, B and C, that have a dependency on another, shared, RAII wrapper, A. For some reason I have a specific use of these components in mind for which I only require to create all these objects at once and destroy them at once (a more complex use might see these objects having different lifetimes). As such I would like to write a higher level component that encapsulates these components and provides an interface to express this specific use. In order to function it will need to inject an A into a B and a C. If this specific use only required the components to exist for a one-off operation then we might write a function like so:
void do_something_useful(data info)
{
// all constructed here
A a(info);
B b(a);
C c(a);

// do something with them
impl(b, c);

// all destructed here
}
We're quite used to seeing code like this, the function controls their lifetime and forwards the work off. However it is not suitable for my purpose, the objects are stateful (Hmm, state-full? ... Full-of-state [smile]) and need to persist between calls in order for this operation to work properly. The next most obvious solution, therefore, is to use a class, D, and have its ctor/dtor control their lifetime and a member function to perform the operation:
class D
{
A a;
B b;
C c;

public:
D(data info) : a(info), b(a), c(a) { }
/* ~D() - no need for an explicit destructor */

void do_something_useful();
};
This looks fine and it works fine, but it has a subtle nuance, it relies on the order of construction of members in a class to operate correctly. This is well defined, it's the order they appear in the class definition (not the order they appear in the initialisation list!). This, to me, feels slightly wrong for some reason. Maybe it's my distrust of other people not knowing their construction rules or maybe it's because, generally, I/we don't usually expect that the order of data members actually matters in the slightest. I have tried to do some searching to find other examples and opinions of this, the best I have is a post by Antheus where he claims that such designs evolve naturally in C++ as consequence of applying the IOC pattern. My question is, how do other people feel about this? Thanks.

Share on other sites
I can't recall any specific case where I would depend on initialization order. In most cases I've encountered the dependency was always external.

It's just an issue with usual C++ complexity, at least the order is guaranteed.

Why not just change D to take A as constructor, whereas A is constructed from info?

If state matters, then copying might be an issue anyway. If it doesn't, then A could be implicitly constructed from info. And if there are other life-cycle issues, then it doesn't make sense to force such designs, and just allocate them differently.

Share on other sites
Quote:
 Original post by AntheusWhy not just change D to take A as constructor, whereas A is constructed from info?
Certainly, if we assume the proposal in my post is bad, then alternatives are fairly easy to produce:
D make_d(data info){    return D(A(info));}
This seems like a likely route.

I could also use pointer types to defer construction to D's constructor body and do it all in there explicitly, but on the heap. In theory it could be the case that B and C are default constructable and fast-swappable/assignable, although they're not here I'm saying.

Share on other sites
I just don't see what the big deal is. Do people you work with usually randomly reorder members in classes for no reason?

Share on other sites
Quote:
 Original post by SiCraneI just don't see what the big deal is. Do people you work with usually randomly reorder members in classes for no reason?

Unlike passing 'this', the examples above do not generate any warnings by the compiler (at least MSVC doesn't). Change the order for whichever, and dependent objects suddenly get garbage.

I've only needed this type of dependency on a handful of very top-level objects, where order is somewhat obvious, and members don't really change.

Elsewhere, I'd simply pass info to A, B and C. That avoids the problem altogether. As always, if the shoe doesn't fit...

Share on other sites
Quote:
 Original post by AntheusChange the order for whichever, and dependent objects suddenly get garbage.

Yes, I understand the technical part of the OP's question. That doesn't address what I asked: do people you work with usually randomly reorder members in classes for no reason?

Share on other sites
Quote:
 Original post by AntheusUnlike passing 'this', the examples above do not generate any warnings by the compiler (at least MSVC doesn't). Change the order for whichever, and dependent objects suddenly get garbage.

G++ will although at the present moment I can not remember which flag gives the warning :)

Share on other sites
Quote:
Original post by magic_man
Quote:
 Original post by AntheusUnlike passing 'this', the examples above do not generate any warnings by the compiler (at least MSVC doesn't). Change the order for whichever, and dependent objects suddenly get garbage.

G++ will although at the present moment I can not remember which flag gives the warning :)

struct X {        int x, y;        X () : y(0), x(0) {}};

main.cc: In constructor X::X()':main.cc:2: warning: X::y' will be initialized aftermain.cc:2: warning:   int X::x'main.cc:3: warning:   when initialized here`

1. 1
2. 2
3. 3
4. 4
Rutin
13
5. 5

• 13
• 10
• 9
• 9
• 11
• Forum Statistics

• Total Topics
633692
• Total Posts
3013355
×