I have a class B that requires an instance of class A to be constructed:
class B
{
B(A* a); // there is no default constructor
};
Now I want to create a class that contains B as a member, so I also need to add A as a member and provide it to B's constructor:
class C
{
C() : a(), b(&a) {}
A a; // 1. initialized as a()
B b; // 2. initialized as b(&a) - OK
};
But the problem is that if someone occasionally changes the order of the variables definition in the class, it will break
class C
{
C() : a(), b(&a) {}
B b; // 1. initialized as b(&a) while "a" uninitialized
A a; // too late...
};
Is there a good way to resolve this without modifying the classes A and B? Thanks.
Is there a good way to resolve this without modifying the classes A and B?
Turn on compiler warnings; for gcc, this is -Wreorder (which is included in -Wall):
cc1plus: warnings being treated as errors
t.cpp: In constructor 'A::A()':
Line 3: warning: 'A::y' will be initialized after
Line 3: warning: 'int A::x'
Line 2: warning: when initialized here
Alternatively, use a lint-like tool that detects this.
But the problem is that if someone occasionally changes the order of the variables definition in the class…
Why would they do this? I suspect you're worrying too much about what might happen. Even so, you can leave a comment in the class:
A a; // Must be listed before member 'b'!
B b;
Don't underestimate the force of well-placed comments. :) Then allow someone who purposefully ignores them to get what they deserve; you are using C++, after all.
Use the well-known C++ idiom called Base-from-Member to solve this problem.
Define a base class as,
class C_Base
{
A a; //moved `A a` to the base class!
C_Base() : a() {}
};
class C : public C_Base
{
C() : b(&a) {}
B b; // 1. initialized as b(&a) while "a" uninitialized
//A a; // too late...
};
Now, a is guaranteed to be initialized before b.
Store b in a unique_ptr, and set it in the body, not in the initializer list:
class C
{
C() :a() {
b = std::unique_ptr<B>(new B(&a));
}
A a;
std::unique_ptr<B> b;
};
One option would be to not explicitly store the A, but instead to use dynamic allocation to create a new A to store in the B:
class C {
public:
C() : b(new A) {
// handled in initialization list
}
private:
B b;
};
Since this guarantees that the A is created before the B, this should prevent this problem from ever occurring.
The problem is that you are shooting yourself in the foot with the third example. In C++ the order of member variables in a class/struct matters. No matter how you go about solving your particular problem, if you pass uninitialized data to a constructor due to poor class design / member layout, you will be working with unitialized data and possibly get undefined behavior, depending on the sort of code in place.
To address your particular example, if B really requires an A and the relationship is one to one, why not create a new class AB that has both an A object and a B object in the right order and pass the address of A to B. That is:
class AB
{
public:
AB():b_(&a_) {}
private:
A a_;
B b_;
};
now class C can avoid the ordering problem by using AB instead of A and B:
class C
{
public:
...
private:
AB ab_;
};
As forementioned, this of course assumes a 1:1 relationship between A and B. If an A object can be shared by many B objects, things get more complicated.
I'm not sure how much control you have over the implementation and structure of C but is it necessary to use the objects themselves in class C? Could you redefine the class to use pointers instead and then move them from the initialization list, e.g.
class C
{
C()
{
a = new A;
b = new B(a);
}
~C() {delete a; delete b;}
A* a;
B* b;
};
This avoids the issue of order in the declaration, but gives you the new issue of ensuring they're created correctly. Also, if you create A LOT of C's very often, an initialization list is slightly faster.
Related
(C++)
I find it a bit troublesome to managing elegantly memory in the following scenario:
I have a class named A, that has a member of class B.
class B has pointer member to class C :
class C{}
class B{
C* c;
}
class A{
B b;
}
in class A's constructor, I initialized class B by passing it a pointer to object of class C I just created.
now, in the destructor of A, I want to free the object of class C I passed to B.
all of the options I know to do that just look for me not very elegant:
make C public in B so I can just do: "delete(b.c);"
create a getter of the c pointer inside B and then do: "delete(b.Getblabla())"
save the pointer I passed as a member of A and then release it: "delete(pointer_to_c)"
do you have some elegant offers?
edit:
hey some clarifications, the reason why A allocates C and passing it to B is that C is an interface and I want B to be initialized with different implementations of C depends in the situation.
A contains an object of type B. So A should not have to do any cleanup itself. Instead, B should clean up the memory, since that is the class that contains an owning pointer.
class B {
C *c;
public:
B(C *c) : c(c) {}
~B() { delete c; }
};
When the destructor of A runs, the destructor of B will be run, which will clean up the memory. Of course, now you will need to define the copy and move operations for B as well. See rule of 3/5/0 for more details.
Instead, B could be written like this:
class B {
std::unique_ptr<C> c;
};
and now you don't have to do any cleanup yourself, since unique_ptr will take care of that.
The simplest and arguably cleanest is probably to just keep the C instance in A in the first place:
class A {
CImplementation c;
B b;
public:
A() : b( &c ) {}
};
If you truly needed it to be dynamically allocated for some reason, use an unique_ptr< C > member and allocate the appropriate C derivative in A's initializer list.
I'm having a problem initializing a shared_ptr member of a class I'm working on.
I have two classes, A and B:
class A {
int _x;
int _y;
public:
A(int, int);
};
A::A(int x, int y) {
_x = x;
_y = y;
}
class B : public A {
std::shared_ptr<A> _a;
public:
B(std::shared_ptr<A>);
};
B::B(std::shared_ptr<A> a) : _a(a) {}
int main() {
std::shared_ptr<A> a = std::make_shared<A>(1, 2);
B b(a);
return 0;
}
I just want class B to hold a std::shared_ptr to an instance of class A.
However, I'm getting the error no matching function for call to A::A() in B's constructor.
I'm confused because I thought the point of the initializer list is to avoid implicitly calling the default constructor for member variables, but it still seems to be trying to call A's default constructor.
Any explanation is appreciated, thanks.
edit: after more messing around, it seems like it complies properly if B does not inherit from A. Still unsure why inheriting from A results in A's default constructor being called from B's constructor.
Since B is derived from A, every B is an A. That means to construct a B, you must also construct an A. However, you do not tell B's constructor how to construct an A, so the default constructor is used.
If you want B to be derived from A and only hold a shared_ptr to A, then A must not do anything you don't want B to do. Here, A has _x and _y.
It's not clear what you really want, but perhaps you want some other base class that both A and B derive from that only has what both A and B should have.
The classic example of inheritance in C++ is something like Instrument being the base class that has members like Play with derived classes like Trumpet and Clarinet having the thing that makes some particular instrument a trumpet. Only what is common to Trumpets and Clarinets should be in Instrument.
When you call B b(a);, you construct a B object using the constructor B::B(std::shared_ptr<A> a).
The issue is in your definition of this constructor. B inherits from A, meaning that B is not just a B, but instead is really an A and B stacked on top of each other. A is the base class, so it is on the bottom. So when you try to construct a B object, the code must first construct the A object at the bottom/base to form the foundation for the B object to exist on. That means that you actually have to tell the code how to construct the A object.
Because you defined a constructor for A that takes two int variables, the compiler does not generate a default constructor for A. Therefore, you must explicitly write out how A should be constructed within B. Constructing the A object can be done in the initializer list of the B object's constructor:
B::B(std::shared_ptr<A> a) : A(0,0), _a(a) {}
Why does the following compile ??
class A{
A(){
A* a = new A() ;
}
} ;
Shouldn't it fail for the same reason something like fails ?
class A{
A obj;
} ;
class A{
A obj;
} ;
is a recursive bomb because A's size is based on A. Obviously that can't be allowed. A doesn't know how big A is and never will. This is easy to catch at compile time.
class A{
A(){
A* a = new A() ;
}
} ;
Is still a recursive bomb, but it will blow up at run time, making it a logical error and not a syntax error. The compiler may emit a warning.
The secret here is that functions defined in a class are, through the magic of inlined functions ([dcl.fct.spec] point 3, but is seems to be point 4 under [dcl.inline] in more recent drafts of the standard), and compiled after the class is defined when it is used in other code (or not at all, as M.M points out below, if the function is never used).
Since the function will be moved outside of the class definition before it is compiled, the size of A is known at the time the function is compiled so it can be constructed safely.
As for A* a, that's just a pointer. The size is baked right in and has no special requirements.
The declaration
class A{
A obj;
} ;
is illegal because you declare an infinite storage this way. Note, that
containing a static field of own class or non-static of base class is legal though.
class A {
public:
static A a;
};
A A::a = A();
class B : A {
A obj;
}
Things like
class A{
A(){
A* a = new A();
}
};
are possible, whatever is declared inside method is a different storage. It is legal by the language rules but semantically it is wrong, a call to such constructor would cause an infinite recursion.
Basically, I have one class that owns another object:
class A()
{
A() { initSystems() };
void initSystems();
B b;
}
class B()
{
B() { //Does stuff that requires 'initSystems()' to be called before }
}
and for 'B' to function, the init systems function needs to be called in A. Is there any 'nice' way to work around this? Like creating the 'B' object later or something?
Sounds like your classes are too tightly coupled. There's many ways to fix this, but it depends on the rest of your design.
Maybe A shouldn't own a B, since A is a dependency of B. You could inject an instance of A into each B as they get instantiated.
Maybe B shouldn't exist and all, and it should be merged into A:
class A()
{
A() {
initSystems();
//Does stuff that requires 'initSystems()' to be called before
}
void initSystems();
// B's methods
}
It's my opinion that most initialization methods are code smells (that is, it suggests a bad design). Some people have given this pattern a name: "Design Smell: Temporal Coupling"
If you desire to keep the B a regular member of A, the two places you can run code before the construction of b are:
the constructor of a base class of A,
in the initializer list of a member of A, for a member declared above b.
If you wish to defer construction of the B, you need to hold the object by indirection or later construct it onto raw storage and when destroying, perform placement destruction.
Most of this has strange smells to it, it may be beneficial to reorganize your code to avoid this kind of structure.
You simply need to change your design so initSystems() is requirement for both A and B.
If you can't do this (although you really should), there are other ways, like dynamic allocation:
class A()
{
A() {
initSystems();
b = std::make_unique<B>();
};
void initSystems();
std::unique_ptr<B> b;
}
I agree with #nanny over the decoupling of the class and merging if possible.
But your scenario seems like in which B is separate entity in your system, hence a class. And A contains a B, hence the composition.
So one way of solving this would be, you keep a reference (pointer) to B in A instead of making B a part of A.
Or you should not access the stuff that is created in initInstance() of A in the constructor of B, and create a method postConstruct in B that you can call from A after call initInstance. Following code explains it,
class A()
{
A()
{
initSystems();
b.postContruct()
}
void initSystems()
{
// do the init instance stuff here.
}
B b;
}
class B()
{
B() {}
void postContruct()
{
//Does stuff that requires 'initSystems()' to be called before
}
}
Consider three classes like this:
class A {
int bar;
};
class B {
A* a;
public:
B(*A na)
: a(na)
{}
~B() {
a->bar = 0;
}
};
class Foo {
A* a;
B b;
public:
Foo()
: a(new A)
, b(a)
{}
~Foo() {
delete a;
}
};
Creating an instance of Foo, results in a Foo with a pointer to an A and a B with the same pointer.
When the instance of Foo is deleted, The pointer a is deleted and then the destructor of b is called, but ~B tries to access a, which was freed in ~Foo, which results in a segmentation fault.
Is there a way to call the destructor of b before running the body of ~Foo?
I know I could solve this, by making either b a pointer or making a a non-pointer. The latter doesn't work if A is abstract and I would like to know if it's possible without making b a pointer.
PS: A and B are both from a library, so I can't change their implementation.
Follow RAII principles.
Change Foo::a to std::unique_ptr<A>. Remove the delete from ~Foo.
It will now be destroyed after the end of ~Foo and after b.~Bar().
Note that members are created in the order of declaration, and destroyed in the opposite order. (The order in initialization lists does not change order of creation, surprisingly). So if you want a to outlive b, simply declare it first.
Create an intermediate class.
class PreFoo
{
A* a:
...
};
class Foo : public PreFoo
{
B b;
...
};
Edit: corrected mistake (thanks #Yakk)
You need to make B a pointer in Foo so you can control the order of deletion in the destructor OR make A a non-pointer and position it before B in the member order of Foo, so that it is destroyed after B, but this makes the code brittle as the order of member declaration is now important. Comment this in your code.