This is somewhat of a broad question that seems to have no one true answer.
I've been confused about the initialization of composed objects for quite some time. I've been formally taught to supply getters and setters for all member data and to favor raw pointers to objects instead of automatic objects - this seems to contrast with what many people on Stack Overflow (such as this popular post) advise.
How, then, should I go about initializing object-composed objects?
This is the way I would attempt initialization using what I've learned in school:
class SmallObject1 {
public:
SmallObject1() {};
};
class SmallObject2 {
public:
SmallObject2() {};
};
class BigObject {
private:
SmallObject1 *obj1;
SmallObject2 *obj2;
int field1;
int field2;
public:
BigObject() {}
BigObject(SmallObject1* obj1, SmallObject2* obj2, int field1, int field2) {
// Assign values as you would expect
}
~BigObject() {
delete obj1;
delete obj2;
}
// Apply getters and setters for ALL members here
};
int main() {
// Create data for BigObject object
SmallObject1 *obj1 = new SmallObject1();
SmallObject2 *obj2 = new SmallObject2();
int field1 = 1;
int field2 = 2;
// Using setters
BigObject *bobj1 = new BigObject();
// Set obj1, obj2, field1, field2 using setters
// Using overloaded contructor
BigObject *bobj2 = new BigObject(obj1, obj2, field1, field2);
return 0;
}
This design is appealing because it's readable (to me). The fact that BigObject
has pointers to its member objects makes it possible to initialize obj1
and obj2
after initialization. However, the dynamic memory could make the program more complicated and confusing down the road, thus ripe for memory leaks. Additionally, the use of getters and setters clutter up the class and may also make the member data too easy to access and mutate.
Is this actually bad practice? I often find times where I need to initialize a member object separately from its owner, which makes automatic objects unappealing. Additionally, I have considered letting larger objects construct their own member objects. This seems to make more sense from a security standpoint, but less sense from an object responsibility standpoint.
I've been formally taught to supply getters and setters for all member data and to favor raw pointers to objects instead of automatic objects
Personally, I have no problem with having setters and getters for all data members. It is a good practice to have and can save a lot of grief especially if you venture into threads. In fact, many UML tools autogenerate them for you. You just need to be aware of what to return. In this particular example, don't return a raw pointer to SmallObject1 *
. Return SmallObject1 * const
instead.
The second part about
raw pointers
is done for educational purposes.
For your main question: the way you structure object storage depends on the larger design. Is BigObject
the only class that will ever use SmallObject
's? Then I would put them completely inside of the BigObject
as private members and do all the memory management there. If SmallObject
's are shared between different objects, and not necessarily of BigObject
class, then I would do what you did. However, I would store the references or pointers to const to them and not delete them in the BigObject
class's destructor - BigObject
didn't allocate them, it thus shouldn't be deleting.