Do constructor object assignments leak memory - c++

Say I have a simple class like this:
class MyObj
{
char* myPtr;
public:
MyObj()
{
myPtr = malloc(30);
}
~MyObj()
{
free(myPtr);
}
}
class TestObject
{
MyObj _myObj;
public:
TestObject(MyObj myObj)
{
_myObj = myObj;
}
};
Does this leak memory? My reasoning is that there is already an instance of MyObj contained in the TestObject by the time the constructor runs, so doesn't that blow away the myPtr before the memory can be freed? Does assigning to a local object call the destructor of the object being replaced? Does the compiler optimize away the assignment of an object instance variable if it is directly assigned in the constructor? I'm coming from C# where an object doesn't get automatically initialized just by declaring a reference type variable, so this is kind of confusing me.
Thanks!

Does this leak memory?
Yes. The assignment of myObj will invoke the default copy-assignment operator, as no override was provided by you. As a result, a member-by-member copy is performed, and the myPtr instance of the assignment target is overwritten with the myPtr instance from the assignment source. There introduces two problems, frequently encountered when violating one or more parts of the Rule of Three/Five/Zero:
You lose the original myPtr content from the target of the assignment. Thus, the original memory uniquely referred to by that pointer is leaked.
You now share the same pointer value in two myPtr members: both the source and the target of the assignment operation.
The latter is especially troubling, as myObj is leaving scope immediately after the assignment is complete within the TestObject constructor. In doing so, myObj will be destroyed, and with that, it's myPtr freed. Further, myObj was passed in to that constructor by value, not reference, so an implicit copy is already likely to have happened (short of elided copy due to rvalue move semantics). Therefore, three MyObj objects may well be hoisting a myPtr that all reference the same memory, and as soon as one releases it, the rest are unknowingly hoisting dangling pointers. Any dereference or free-ing of those pointers will invoke undefined behavior.
Does assigning to a local object call the destructor of the object being replaced?
Destructors are only invoked to live to their namesake. I.e., they're only invoked when an object is being destroyed (manual invoke of destructors for placement-new semantics notwithstanding). Copy-assignment doesn't do that unless temporaries are introduced, and that isn't the case in your code.
Does the compiler optimize away the assignment of an object instance variable if it is directly assigned in the constructor?
No, but a member initialization list can assist in that regard.
Modern C++ programming techniques frequently use RAII to accomplish what you seem to be trying in a number of ways, depending on the goal you're really trying to achieve.
Unique Data Per Instance
If the goal is unique dynamic data per instance, you can accomplish this easily with either std::vector<char>, or simply std::string, depending on the underlying need. Both are RAII data types and are usually ample for dynamic memory management needs.
class MyObj
{
std::vector<char> myData;
public:
MyObj() : myData(30)
{
}
}
class TestObject
{
MyObj _myObj;
public:
TestObject(MyObj myObj)
: _myObj(std::move(myObj))
{
}
};
This eliminates the need to a destructor in MyObj, and utilizes move semantics as well as the aforementioned member initialization list in the TestObject constructor. All instances of MyObj will hoist a distinct vector of char. All assignment operations for MyObj and TestObject work with default implementations.
Assignments Share Memory
Unlikely you desire this, but it is none-the-less feasible:
class MyObj
{
std::shared_ptr<char> myPtr;
public:
MyObj() : myPtr(new char[30])
{
}
};
class TestObject
{
MyObj _myObj;
public:
TestObject(MyObj myObj)
: _myObj(std::move(myObj))
{
}
};
Similar code, but different member type. Now myPtr is a shared pointer to an array of char. Any assignment to a different myPtr joins the share list. In short, assignment means both object reference the same data, and reference-counting ensures the last-man-standing sweeps up the mess.
Note: There is the possibility of a memory leak using shared pointers like this, as the new may succeed, but the shared data block of the shared-pointer may throw an exception. This is addressed in C++17,
where std::make_shared supports array-allocation
These are just a few ways of doing what you may be trying to accomplish. I encourage you to read about the Rule of Three/Five/Zero and about RAII concepts both at the links provided and on this site. There are plenty of examples that will likely answer further questions you may have.

Related

Caveats and risks of calling a constructor and destructor like common methods?

There's a point in my program where the state of a certain object needs to be reset "to factory defaults". The task boils down to doing everything that is written in the destructor and constructor. I could delete and recreate the object - but can I instead just call the destructor and the constructor as normal objects? (in particular, I don't want to redistribute the updated pointer to the new instance as it lingers in copies in other places of the program).
MyClass {
public:
MyClass();
~MyClass();
...
}
void reinit(MyClass* instance)
{
instance->~MyClass();
instance->MyClass();
}
Can I do this? If so, are there any risks, caveats, things I need to remember?
If your assignment operator and constructor are written correctly, you should be able to implement this as:
void reinit(MyClass* instance)
{
*instance = MyClass();
}
If your assignment operator and constructor are not written correctly, fix them.
The caveat of implementing the re-initialisation as destruction followed by construction is that if the constructor fails and throws an exception, the object will be destructed twice without being constructed again between the first and second destruction (once by your manual destruction, and once by the automatic destruction that occurs when its owner goes out of scope). This has undefined behaviour.
You could use placement-new:
void reinit(MyClass* instance)
{
instance->~MyClass();
new(instance) MyClass();
}
All pointers remain valid.
Or as a member function:
void MyClass::reinit()
{
~MyClass();
new(this) MyClass();
}
This should be used carefully, see http://www.gotw.ca/gotw/023.htm, which is about implementing an assignement operator with this trick, but some points apply here too:
The constructor should not throw
MyClass should not be used as a base class
It interferes with RAII, (but this could be wanted)
Credit to Fred Larson.
Can I do this? If so, are there any risks, caveats, things I need to remember?
No you can't do this. Besides it's technically possible for the destructor call, it will be just undefined behavior.
Supposed you have implemented the assignment operator of your class correctly, you could just write:
void reinit(MyClass* instance) {
*instance = MyClass();
}
You should use a smart pointer and rely on move semantics to get the behavior you want.
auto classObj = std::make_unique<MyClass>();
This creates a wrapped pointer that handles the dynamic memory for you. Suppose you are ready to reset classObj to the factory defaults, all you need is:
classObj = std::make_unique<MyClass>();
This "move-assignment" operation will call the destructor of MyClass, and then reassign the classObj smart pointer to point to a newly constructed instance of MyClass. Lather, rinse, repeat as necessary. In other words, you don't need a reinit function. Then when classObj is destroyed, its memory is cleaned up.
instance->MyClass(); is illegal, you must get a compilation error.
instance->~MyClass(); is possible. This does one of two things:
Nothing, if MyClass has a trivial destructor
Runs the code in the destructor and ends the lifetime of the object, otherwise.
If you use an object after its lifetime is ended, you cause undefined behaviour.
It is rare to write instance->~MyClass(); unless you either created the object with placement new in the first place, or you are about to re-create the object with placement new.
In case you are unaware, placement new creates an object when you already have got storage allocated. For example this is legal:
{
std::string s("hello");
s.~basic_string();
new(&s) std::string("goodbye");
std::cout << s << '\n';
}
You can try using placement new expression
new (&instance) MyClass()

Creating a class object in c++

First i am from JAVA.
In java we create class object like this.
Example example=new Example();
The Example class can have constructor or cannot have constructor.
I can use the same in c++ like this
Example* example=new Example();
Where constructor is compulsory.
From this tutorial http://www.cplusplus.com/doc/tutorial/classes/
I got that we can create object like this.
Example example;
Which do not require an constructor.
I have two questions.
What is the difference between both the way of creating class objects.
If I am creating object like Example example; how to use that in an singleton class.
like I usually do like this.
Sample* Singleton::get_sample() {
if (sample == NULL) {
sample = new Sample();
}
return sample;
}
Please guide me if I am wrong.
I can use the same in c++ like this [...] Where constructor is compulsory. From this tutorial I got that we can create object like this [...] Which do not require an constructor.
This is wrong. A constructor must exist in order to create an object. The constructor could be defined implicitly by the compiler under some conditions if you do not provide any, but eventually the constructor must be there if you want an object to be instantiated. In fact, the lifetime of an object is defined to begin when the constructor routine returns.
From Paragraph 3.8/1 of the C++11 Standard:
[...] The lifetime of an object of type T begins when:
— storage with the proper alignment and size for type T is obtained, and
— if the object has non-trivial initialization, its initialization is complete.
Therefore, a constructor must be present.
1) What is the difference between both the way of creating class objects.
When you instantiate object with automatic storage duration, like this (where X is some class):
X x;
You are creating an object which will be automatically destroyed when it goes out of scope. On the other hand, when you do:
X* x = new X();
You are creating an object dynamically and you are binding its address to a pointer. This way, the object you created will not be destroyed when your x pointer goes out of scope.
In Modern C++, this is regarded as a dubious programming practice: although pointers are important because they allow realizing reference semantics, raw pointers are bad because they could result in memory leaks (objects outliving all of their pointers and never getting destroyed) or in dangling pointers (pointers outliving the object they point to, potentially causing Undefined Behavior when dereferenced).
In fact, when creating an object with new, you always have to remember destroying it with delete:
delete x;
If you need reference semantics and are forced to use pointers, in C++11 you should consider using smart pointers instead:
std::shared_ptr<X> x = std::make_shared<X>();
Smart pointers take care of memory management issues, which is what gives you headache with raw pointers. Smart pointers are, in fact, almost the same as Java or C# object references. The "almost" is necessary because the programmer must take care of not introducing cyclic dependencies through owning smart pointers.
2) If i am creating object like Example example; how to use that in an singleton class.
You could do something like this (simplified code):
struct Example
{
static Example& instance()
{
static Example example;
return example;
}
private:
Example() { }
Example(Example const&) = delete;
Example(Example&&) = delete;
Example& operator = (Example const&) = delete;
Example& operator = (Example&&) = delete;
};
Example example;
This is a declaration of a variable named example of type Example. This will default-initialize the object which involves calling its default constructor. The object will have automatic storage duration which means that it will be destroyed when it goes out of scope.
Example* example;
This is a declaration of a variable named example which is a pointer to an Example. In this case, default-initialization leaves it uninitialized - the pointer is pointing nowhere in particular. There is no Example object here. The pointer object has automatic storage duration.
Example* example = new Example();
This is a declaration of a variable named example which is a pointer to an Example. This pointer object, as above, has automatic storage duration. It is then initialized with the result of new Example();. This new expression creates an Example object with dynamic storage duration and then returns a pointer to it. So the example pointer is now pointing to that dynamically allocated object. The Example object is value-initialized which will call a user-provided constructor if there is one or otherwise initialise all members to 0.
Example* example = new Example;
This is similar to the previous line. The difference is that the Example object is default-initialized, which will call the default constructor of Example (or leave it uninitialized if it is not of class type).
A dynamically allocated object must be deleted (probably with delete example;).
There is two ways to make/create object in c++.
First one is :
MyClass myclass; // if you don;t need to call rather than default constructor
MyClass myclass(12); // if you need to call constructor with parameters
Second one is :
MyClass *myclass = new MyClass();// if you don;t need to call rather than default constructor
MyClass *myclass = new MyClass(12);// if you need to call constructor with parameters
In c++ if you use new keyword, object will be stored in heap. it;s very useful if you are using this object long time of period and if you use first method, it will be stored in stack. it can be used only short time period. Notice : if you use new keyword, remember it will return pointer value. you should declare name with *. If you use second method, it doesn;t delete object in the heap. you must delete by yourself using delete keyword;
delete myclass;
1) What is the difference between both the way of creating class objects.
a) pointer
Example* example=new Example();
// you get a pointer, and when you finish it use, you have to delete it:
delete example;
b) Simple declaration
Example example;
you get a variable, not a pointer, and it will be destroyed out of scope it was declared.
2) Singleton C++
This SO question may helps you
First of all, both cases calls a constructor. If you write
Example *example = new Example();
then you are creating an object, call the constructor and retrieve a pointer to it.
If you write
Example example;
The only difference is that you are getting the object and not a pointer to it. The constructor called in this case is the same as above, the default (no argument) constructor.
As for the singleton question, you must simple invoke your static method by writing:
Example *e = Singleton::getExample();
1)What is the difference between both the way of creating class
objects.
First one is a pointer to a constructed object in heap (by new).
Second one is an object that implicitly constructed. (Default constructor)
2)If i am creating object like Example example; how to use that in an
singleton class.
It depends on your goals, easiest is put it as a member in class simply.
A sample of a singleton class which has an object from Example class:
class Sample
{
Example example;
public:
static inline Sample *getInstance()
{
if (!uniqeInstance)
{
uniqeInstance = new Sample;
}
return uniqeInstance;
}
private:
Sample();
virtual ~Sample();
Sample(const Sample&);
Sample &operator=(const Sample &);
static Sample *uniqeInstance;
};
Example example;
Here example is an object on the stack.
Example* example=new Example();
This could be broken into:
Example* example;
....
example=new Example();
Here the first statement creates a variable example which is a "pointer to Example". When the constructor is called, memory is allocated for it on the heap (dynamic allocation). It is the programmer's responsibility to free this memory when it is no longer needed. (C++ does not have garbage collection like java).
In the first case you are creating the object on the heap using new.
In the second case you are creating the object on the stack, so it will be disposed of when going out of scope.
In C++ you'll need to delete objects on the heapexplicitly using delete when you don't Need them anymore.
To call a static method from a class, do
Singleton* singleton = Singleton::get_sample();
in your main-function or wherever.

Does dynamically allocated memory for data members of a C++ class frees when class object is finalizing?

I've this C++ class:
class test{
char* p;
SomeClass* someObject;
test(){
...
p = (char*) malloc(1000);
someObject = new SomeClass();
...
}
~test(){}
}
Do I need to call free(p) or delete someObject explicitly in test destructor in order to free their allocated memory or that memory will free automatically?
You need to free all dynamically allocated memory in the destructor. This does not get done automatically.
Your class contains two pointers, and essentially has no control over what these point to. In fact, these could point to objects that you are not allowed to delete, for example:
struct Foo {};
struct Bar {
Foo* f_;
Foo(Foo* f) : f(f_) {}
};
int main() {
Foo f;
Bas b(&f); // b has a Foo ptr, but should it delete it?
}
So you can see that it doesn't really make sense for pointer data members to be deleted automatically.
As a general rule, if your class manages resources1, then you should take care of copy construction and assignment; that means, you should either disable them if that makes sense for the class, or provide implementation for them because the compiler generated ones would not work. For detail discussion on this topic, see the rule of three, and extensive discussions on stackoverflow:
What is The Rule of Three?
Rule-of-Three becomes Rule-of-Five with C++11?
If you don't follow this rule, then the default copy constructor and assignment operation will make a shallow copy and you will have more than one instance having pointers to the same dynamically allocated objects, which they will all try to delete upon destruction.
You can avoid manually deleting objects created with new by using smart pointers. In your case, where the class obviously owns the dynamically allocated object,you should look at C++11's std::unique_ptr or boost::scoped_ptr
Finally, you can really avoid all memory management problems by avoiding pointers all together, unless you really need to. You could replace your char* by an std::string for example:
class test{
std::string p;
SomeClass someObject;
//test() : someObject() {} // default construction is probably OK...
};
1. That is, it allocates and deallocates memory, or opens and closes network connection, or creates and destroy mutexes and so on.
Yes, you have to free anything you malloc and delete everything you new.
You can also avoid that by not storing pointers in your class.
class test{
public:
std::string p;
SomeClass someObject;
};
Yes, you need.
If you don't want, you can use the Smart Pointer
Yes, you need to free them explicitly. Pointer as a data type does not have any destructor. Compiler/execution enviroment does not have any means to guess if pointer points to anything meaningfull or not. Even if the value is meaningfull, it may point to some static object for example. Or it can point to some field of a bigger object. Compiler is not doing any automatic cleanup on pointers.
The memory is technically leaked if you do not reclaim it when the instance of test is destructed. You could use a smart pointer instead to avoid calling free or delete explicitly in the destructor.
struct Free { void operator () (void *p) const { free(p); } };
class test {
std::unique_ptr<char, Free> p;
std::unique_ptr<SomeClass> someObject;
test () : p(static_cast<char *>(malloc(1000)),
someObject(new SomeClass)
{ //...
}
~test () {}
};
This uses the destructor of the smart pointer to perform the clean up action for you.
If test were only used as const global instances, then it is less important to implement the cleanup since the memory would not be reclaimed until the execution had ended anyway. But it is good practice to always implement the cleanup, because it would make the code correct now, and test may be used differently in the future.

Is it undefined to initialize a class member in overloaded operator new?

Take a small example where, I am trying to find out if a variable is allocated on heap or not:
struct A
{
bool isOnHeap;
A () {} // not touching isOnHeap
~A () {}
void* operator new (size_t size)
{
A* p = (A*) malloc(size);
p->isOnHeap = true; // setting it to true
return p;
}
void operator delete (void *p) { free(p); }
};
It gives expected result in g++-4.5 (with warning for stack object). Is it ill defined
to do such operations ?
You can't initialize class members in an overloaded operator new because the object's lifetime hasn't started. You can only initialize members during the construction of the object.
You have no guarantee that the implementation won't wipe the memory between the time operator new returns and the time the object's construction starts or that during object construction members that are specified to have an indeterminate value by the standard (e.g. because they are POD and not explicitly initialized in the constructor like isOnHeap) aren't deliberately set to something by the implementation.
Note that A has a non-trivial constructor (it is user-declared), so its lifetime doesn't start when the storage for the object is allocated (ISO/IEC 14882:2003, 3.8 [basic.life] / 1) and the program has undefined behavior if it uses a pointer to the storage for the object to access a non-static data member (3.8 / 5). Even if A was a POD type, it's value after the completion of the new-expression would still be indeterminate rather than necessarily being related to the values in the bytes in the storage for the object before the new-expression was evaluated.
As Charles said, the object only comes to lifetime after it has been newed, so setting data within your implementation of new is rather dangerous.
Also, when your developers use tools like Lint, there's a big chance that it complains that the member isOnHeap is not initialized in the constructor. If then someone thinks "hey, Lint is right, let's initialize isOnHeap in the constructor of A", this will undermine the mechanism that you try to achieve.
There is a second case of which you probably didn't think. Suppose that someone writes this:
class MyClass
{
public:
...
private:
struct A m_a;
};
int main()
{
MyClass *myVariable = new MyClass();
}
Then your implementation of new will not be called. Nevertheless the instance of A is allocated on the heap (as part of the MyClass instance).
Can you explain why you want to know whether something has been allocated on the heap or not? Maybe there's another, more elegant solution to your problem.
Even when not considering the operator new itself (which is nonstandard and I would even say ugly, but knowing the exact details of some particular compiler it might be workable), there is another problem with this, which renders it useless anyway: You have no guarantee the value od isOnHeap will not be true when allocated on the stack. The stack is not initialized and any garbage from function invocations done before can be found there.

Class members that are objects - Pointers or not? C++

If I create a class MyClass and it has some private member say MyOtherClass, is it better to make MyOtherClass a pointer or not? What does it mean also to have it as not a pointer in terms of where it is stored in memory? Will the object be created when the class is created?
I noticed that the examples in QT usually declare class members as pointers when they are classes.
If I create a class MyClass and it has some private member say MyOtherClass, is it better to make MyOtherClass a pointer or not?
you should generally declare it as a value in your class. it will be local, there will be less chance for errors, fewer allocations -- ultimately fewer things that could go wrong, and the compiler can always know it is there at a specified offset so... it helps optimization and binary reduction at a few levels. there will be a few cases where you know you'll have to deal with pointer (i.e. polymorphic, shared, requires reallocation), it is typically best to use a pointer only when necessary - especially when it is private/encapsulated.
What does it mean also to have it as not a pointer in terms of where it is stored in memory?
its address will be close to (or equal to) this -- gcc (for example) has some advanced options to dump class data (sizes, vtables, offsets)
Will the object be created when the class is created?
yes - the size of MyClass will grow by sizeof(MyOtherClass), or more if the compiler realigns it (e.g. to its natural alignment)
Where is your member stored in memory?
Take a look at this example:
struct Foo { int m; };
struct A {
Foo foo;
};
struct B {
Foo *foo;
B() : foo(new Foo()) { } // ctor: allocate Foo on heap
~B() { delete foo; } // dtor: Don't forget this!
};
void bar() {
A a_stack; // a_stack is on stack
// a_stack.foo is on stack too
A* a_heap = new A(); // a_heap is on stack (it's a pointer)
// *a_heap (the pointee) is on heap
// a_heap->foo is on heap
B b_stack; // b_stack is on stack
// b_stack.foo is on stack
// *b_stack.foo is on heap
B* b_heap = new B(); // b_heap is on stack
// *b_heap is on heap
// b_heap->foo is on heap
// *(b_heap->foo is on heap
delete a_heap;
delete b_heap;
// B::~B() will delete b_heap->foo!
}
We define two classes A and B. A stores a public member foo of type Foo. B has a member foo of type pointer to Foo.
What's the situation for A:
If you create a variable a_stack of type A on the stack, then the object (obviously) and its members are on the stack too.
If you create a pointer to A like a_heap in the above example, just the pointer variable is on the stack; everything else (the object and it's members) are on the heap.
What does the situation look like in case of B:
you create B on the stack: then both the object and its member foo are on the stack, but the object that foo points to (the pointee) is on the heap. In short: b_stack.foo (the pointer) is on the stack, but *b_stack.foo the (pointee) is on the heap.
you create a pointer to B named b_heap: b_heap (the pointer) is on the stack, *b_heap (the pointee) is on the heap, as well as the member b_heap->foo and *b_heap->foo.
Will the object be automagically created?
In case of A: Yes, foo will automatically be created by calling the implicit default constructor of Foo. This will create an integer but will not intitialize it (it will have a random number)!
In case of B: If you omit our ctor and dtor then foo (the pointer) will also be created and initialized with a random number which means that it will point to a random location on the heap. But note, that the pointer exists! Note also, that the implicit default constructor won't allocate something for foo for you, you have to do this explicitly. That's why you usually need an explicit constructor and a accompanying destructor to allocate and delete the pointee of your member pointer. Don't forget about copy semantics: what happens to the pointee if your copy the object (via copy construction or assignment)?
What's the point of all of this?
There are several use cases of using a pointer to a member:
To point to an object you don't own. Let's say your class needs access to a huge data structure that is very costly to copy. Then you could just save a pointer to this data structure. Be aware that in this case creation and deletion of the data structure is out of the scope of your class. Someone other has to take care.
Increasing compilation time, since in your header file the pointee does not have to be defined.
A bit more advanced; When your class has a pointer to another class that stores all private members, the "Pimpl idiom": http://c2.com/cgi/wiki?PimplIdiom, take also a look at Sutter, H. (2000): Exceptional C++, p. 99--119
And some others, look at the other answers
Advice
Take extra care if your members are pointers and you own them. You have to write proper constructors, destructors and think about copy constructors and assignment operators. What happens to the pointee if you copy the object? Usually you will have to copy construct the pointee as well!
In C++, pointers are objects in their own right. They're not really tied to whatever they point to, and there's no special interaction between a pointer and its pointee (is that a word?)
If you create a pointer, you create a pointer and nothing else. You don't create the object that it might or might not point to. And when a pointer goes out of scope, the pointed-to object is unaffected. A pointer doesn't in any way affect the lifetime of whatever it points to.
So in general, you should not use pointers by default. If your class contains another object, that other object shouldn't be a pointer.
However, if your class knows about another object, then a pointer might be a good way to represent it (since multiple instances of your class can then point to the same instance, without taking ownership of it, and without controlling its lifetime)
The common wisdom in C++ is to avoid the use of (bare) pointers as much as possible. Especially bare pointers that point to dynamically allocated memory.
The reason is because pointers make it more difficult to write robust classes, especially when you also have to consider the possibility of exceptions being thrown.
I follow the following rule: if the member object lives and dies with the encapsulating object, do not use pointers. You will need a pointer if the member object has to outlive the encapsulating object for some reason. Depends on the task at hand.
Usually you use a pointer if the member object is given to you and not created by you. Then you usually don't have to destroy it either.
This question could be deliberated endlessly, but the basics are:
If MyOtherClass is not a pointer:
The creation and destruction of MyOtherClass is automatic, which can reduce bugs.
The memory used by MyOtherClass is local to the MyClassInstance, which could improve performance.
If MyOtherClass is a pointer:
The creation and destruction of MyOtherClass is your responsibility
MyOtherClass may be NULL, which could have meaning in your context and could save memory
Two instances of MyClass could share the same MyOtherClass
Some advantages of pointer member:
The child (MyOtherClass) object can have different lifetime than its parent (MyClass).
The object can possibly be shared between several MyClass (or other) objects.
When compiling the header file for MyClass, the compiler doesn't necessarily have to know the definition of MyOtherClass. You don't have to include its header, thus decreasing compile times.
Makes MyClass size smaller. This can be important for performance if your code does a lot of copying of MyClass objects. You can just copy the MyOtherClass pointer and implement some kind of reference counting system.
Advantages of having the member as an object:
You don't have to explicitely write code to create and destroy the object. It's easier and and less error-prone.
Makes memory management more efficient because only one block of memory needs to be allocated instead of two.
Implementing assignment operators, copy/move constructors etc is much simpler.
More intuitive
If you make the MyOtherClass object as member of your MyClass:
size of MyClass = size of MyClass + size of MyOtherClass
If you make the MyOtherClass object as pointer member of your MyClass:
size of MyClass = size of MyClass + size of any pointer on your system
You might want to keep MyOtherClass as a pointer member because it gives you the flexibility to point it to any other class that is derived from it. Basically helps you implement dynamice polymorphism.
It depends... :-)
If you use pointers to say a class A, you have to create the object of type A e.g. in the constructor of your class
m_pA = new A();
Moreover, don't forget to destroy the object in the destructor or you have a memory leak:
delete m_pA;
m_pA = NULL;
Instead, having an object of type A aggregated in your class is easier, you can't forget to destroy it, because this is done automatically at the end of lifetime of your object.
On the other hand, having a pointer has the following advantages:
If your object is allocated on the
stack and type A uses a lot of memory
this won't be allocated from the
stack but from the heap.
You can construct your A object later (e.g. in a method Create) or destroy it earlier (in method Close)
An advantage of the parent class maintaining the relation to a member object as a (std::auto_ptr) pointer to the member object is that you can forward declare the object rather than having to include the object's header file.
This decouples the classes at build time allowing to modify the member object's header class without causing all the clients of your parent class to be recompiled as well even though they probably do not access the member object's functions.
When you use an auto_ptr, you only need to take care of construction, which you could typically do in the initializer list. Destruction along with the parent object is guaranteed by the auto_ptr.
The simple thing to do is to declare your members as objects. This way, you do not have to care about copy construction, destruction and assignment. This is all taken care of automatically.
However, there are still some cases when you want pointers. After all, managed languages (like C# or Java) actually hold member objects by pointers.
The most obvious case is when the object to be kept is polymorphic. In Qt, as you pointed out, most objects belong to a huge hierarchy of polymorphic classes, and holding them by pointers is mandatory since you don't know at advance what size will the member object have.
Please beware of some common pitfalls in this case, especially when you deal with generic classes. Exception safety is a big concern:
struct Foo
{
Foo()
{
bar_ = new Bar();
baz_ = new Baz(); // If this line throw, bar_ is never reclaimed
// See copy constructor for a workaround
}
Foo(Foo const& x)
{
bar_ = x.bar_.clone();
try { baz_ = x.baz_.clone(); }
catch (...) { delete bar_; throw; }
}
// Copy and swap idiom is perfect for this.
// It yields exception safe operator= if the copy constructor
// is exception safe.
void swap(Foo& x) throw()
{ std::swap(bar_, x.bar_); std::swap(baz_, x.baz_); }
Foo& operator=(Foo x) { x.swap(*this); return *this; }
private:
Bar* bar_;
Baz* baz_;
};
As you see, it is quite cumbersome to have exception safe constructors in the presence of pointers. You should look at RAII and smart pointers (there are plenty of resources here and somewhere else on the web).