This is a design question, assuming C++ and a reference counted object hierarchy. A lot of classes in my codebase derive from a common base class (ObjectBase), which implements retain() and release() methods to increase and decrease the reference count of an object instance.
Every instance of an object may be created on the stack or on the heap, using a number of user definable memory allocators. In order for the object instance to commit suicide (delete this) in the release() method if the retainCount reaches 0, the instance must know which allocator it has been constructed with.
At the moment, I am allocating memory for an object instance using an arbitrary allocator, then call placement new to construct the object instance and call a setAllocator() method on the object to set the allocator it has been created with. If the object has been constructed on the stack, the allocator is set to NULL and release() will not call delete. This process is very redundant and potentially error prone (memory leaks, if I forget to call setAllocator, etc...) Ideally I would want to make this a one-step process like this:
Object* o = myPoolAllocator.allocate<Object>(constructor arguments... );
But this makes it very difficult to support and arbitrary number of constructor arguments.
I am just looking for ideas on how to solve this problem. I really like the idea of being able to reference count objects without having to rely on a smart pointer, especially since most classes derive from a common base, anyways.
Thanks for your help.
Florian
Have a look at this article: Overloading New in C++ . You could overload the new operator for ObjectBase so that it takes your allocator as a parameter and does the rest of the job:
void *ObjectBase::operator new(size_t size, Allocator *allocator) {
void *ptr = allocator->allocate(size);
// Hack to pre-initialize member before constructor is called
ObjectBase *obj = static_cast<ObjectBase *>(ptr);
obj->setAllocator(allocator);
return ptr;
}
Normally, the operator is supposed to just return a pointer to the allocated memory, but since you need access to the new object to call your setAllocator method, I've included a hack that should (but may not) work. Note that the actual ObjectBase constructor is called after the above function returns, so you should make sure that your constructor does not re-initialize the allocator member.
And then a similar overload for delete:
void ObjectBase::operator delete(void *ptr) {
ObjectBase *obj = static_cast<ObjectBase *>(ptr);
obj->getAllocator()->free(ptr);
}
You would then create objects by calling new (allocator) SomeClass(...) where SomeClass derives from ObjectBase.
Edit: One potential problem with this is that you cannot allocate objects on the stack any more, because there is no way to initialize the allocator to NULL without affecting the how the overloaded new works.
Update: There is one last (dirty) hack to get it working with both stack and dynamic allocation. You can make new set a global variable (a class static member would work as well) pointing to the current allocator and the constructor could consume this and reset it to NULL. At all other times, this global will already be NULL so an object constructed on the stack will get a NULL allocator.
Allocator *currentAllocator = NULL;
void *ObjectBase::operator new(size_t size, Allocator *allocator) {
currentAllocator = allocator;
return allocator->allocate(size);
}
ObjectBase::ObjectBase() {
setAllocator(currentAllocator);
currentAllocator = NULL;
}
Related
Why C++ hasn't placement delete that directly corresponds to the placement new, i.e. calls the destructor and calls appropriate placement delete operator?
For example:
MyType *p = new(arena) MyType;
...
//current technique
p->~MyType();
operator delete(p, arena);
//proposed technique
delete(arena) p;
operator delete is unique in being a non-member or static member function that is dynamically dispatched. A type with a virtual destructor performs the call to its own delete from the most derived destructor.
struct abc {
virtual ~abc() = 0;
};
struct d : abc {
operator delete() { std::cout << "goodbye\n"; }
};
int main() {
abc *p = new d;
delete p;
}
(Run this example.)
For this to work with placement delete, the destructor would have to somehow pass the additional arguments to operator delete.
Solution 1: Pass the arguments through the virtual function. This requires a separate virtual destructor for every static member and global operator delete overload with different arguments.
Solution 2: Let the virtual destructor return a function pointer to the caller specifying what operator delete should be called. But if the destructor does lookup, this hits the same problem of requiring multiple virtual function definitions as #1. Some kind of abstract overload set would have to be created, which the caller would resolve.
You have a perfectly good point, and it would be a nice addition to the language. Retrofitting it into the existing semantics of delete is probably even possible, in theory. But most of the time we don't use the full functionality of delete and it suffices to use a pseudo-destructor call followed by something like arena.release(p).
Probably because there was syntax for explicitly calling a destructor without deallocation (exactly as in your question), but no syntax for explicit construction in raw memory?
Actually there is a placement delete which is called by the implementation for an object that was "allocated" using placement new if the constructor threw an exception.
From Wikipedia.
The placement delete functions are called from placement new expressions. In particular, they are called if the constructor of the object throws an exception. In such a circumstance, in order to ensure that the program does not incur a memory leak, the placement delete functions are called.
The whole point of placement new is to separate object creation from its memory management. So it makes no sense to tie it back during object destruction.
If memory for your objects is from heap and you want same lifetime for objects and their memory just use operator new and operator delete, maybe overriding them if you want any special behavior.
Placement new is good for example in vector, which keeps a large chunk of raw memory and creates and destroys object inside of it, but without releasing memory.
I was making a memory pool allocator for a project I am working on. My pool allocator returns chunks of memory fine however my class inherits from another class.
MyClass *fx = (MyClass*)pool->allocateEffect(sizeof(MyClass));
*fx = MyClass();
This doesn't setup the vtable for me. I did some searching and found out the new operator can take in a chunk of memory.
MyClass *fx = (MyClass*)pool->allocateEffect(sizeof(MyClass));
fx = new(fx)MyClass();
And this will initialize the vptr. So I was wondering if there is anyway to allocate the vptr my self or is it strictly up to the compilers whim?
new(fx)MyClass()
This is called "placement new" and will actually call a constructor to actually create an object.
Until you created that object in the memory you allocated, it simply does not exist (as an object of that type) so it is just raw untyped memory that you cast to something, which results in undefined behavior.
I would suggest that you make your function a template like.
template<class T>
T* allocateEffect() { return new (allocate_some_memory(sizeof(T))) T(); }
adding proper variadic templates and forwarding for constructor arguments is left as an exercise to the reader.
Im new to this and just wanted to ask a quick question about deleting objects.
I have an object called MyClass1 and from it I have a number of other classes, MyClassA, MyClassB etc.
Now should I do this in MyClass1:
MyClass1::~MyClass1()
{
delete MyClassA;
delete MyClassB;
}
Or will everything created in MyClass1 automatically be deleted when I delete MyClass1?
Also, if I have more objects created in MyClassA and MyClassB, will these also have to be deleted manually in their respective class?
Thanks
If you're asking this, you're just learning C++, so the best advice is - neither. You should know about this stuff (dynamic allocation & memory management - see Guillaume's answer for this), but what you really should do is use RAII (google this). The proper C++ way of doing it would be:
struct MyClass1
{
MyClassA mA;
std::shared_ptr<MyClassB> mB;
MyClass1() : mB(new MyClassB)
{
}
};
See? No more destructor, which means you also don't need a copy constructor or copy assignment operator (which is where Guillaume's answer is flawed - it's missing the last two).
call delete operator only if you have created your objects with new operator
struct MyClass1
{
MyClassA mA;
MyClassB * mB;
MyClass1()
{
mB = new MyClassB;
}
~MyClass1()
{
delete mB;
}
};
You can't delete objects that aren't pointers because that's not the purpose of delete. It's meant to free dynamic memory associated with an object. That is, whatever is created with new must be deleted. You can have pointers to a class, and they can be deleted. But since nothing was allocated with new, there's no need to use delete. The class will in fact be destructed from memory at the end of the scope in which it is created. Those objects are allocated on the stack while dynamic memory is on the heap. Objects on the stack have automatic storage duration (deleted at the end of its scope, unless its declared static in which case it has "static" storage duration); moreover, objects on the heap have dynamic storage duration. Dynamic memory in C++ is controlled by you, that's why we are given new and delete (because C++ expects us to handle the memory ourselves). And otherwise deleting an object not constructed with new is undefined behavior and may lead to a crash.
If Qt, use QPointer! It is a smart pointer: nothing needed in destructor.
#include <QPointer>
class MyClass1
{
QPointer<MyClassA> pA;
QPointer<MyClassB> pB;
};
delete is applied to objects, not to classes. As a rule, calling delete (or arranging to have it called automatically, via a shared pointer, or with the RAII idiom in general) is necessary only if you called new to create the object. The exception is the return value of some (library?) call being an object that the (library's?) documentation states explicitly that the caller has to dispose of with delete (in which case, think of the call as a wrapper around a new that you have become responsible for.) Of course, APIs like that should be avoided if at all possible.
Basic Question: when does a program call a class' destructor method in C++? I have been told that it is called whenever an object goes out of scope or is subjected to a delete
More specific questions:
1) If the object is created via a pointer and that pointer is later deleted or given a new address to point to, does the object that it was pointing to call its destructor (assuming nothing else is pointing to it)?
2) Following up on question 1, what defines when an object goes out of scope (not regarding to when an object leaves a given {block}). So, in other words, when is a destructor called on an object in a linked list?
3) Would you ever want to call a destructor manually?
1) If the object is created via a pointer and that pointer is later deleted or given a new address to point to, does the object that it was pointing to call its destructor (assuming nothing else is pointing to it)?
It depends on the type of pointers. For example, smart pointers often delete their objects when they are deleted. Ordinary pointers do not. The same is true when a pointer is made to point to a different object. Some smart pointers will destroy the old object, or will destroy it if it has no more references. Ordinary pointers have no such smarts. They just hold an address and allow you to perform operations on the objects they point to by specifically doing so.
2) Following up on question 1, what defines when an object goes out of scope (not regarding to when an object leaves a given {block}). So, in other words, when is a destructor called on an object in a linked list?
That's up to the implementation of the linked list. Typical collections destroy all their contained objects when they are destroyed.
So, a linked list of pointers would typically destroy the pointers but not the objects they point to. (Which may be correct. They may be references by other pointers.) A linked list specifically designed to contain pointers, however, might delete the objects on its own destruction.
A linked list of smart pointers could automatically delete the objects when the pointers are deleted, or do so if they had no more references. It's all up to you to pick the pieces that do what you want.
3) Would you ever want to call a destructor manually?
Sure. One example would be if you want to replace an object with another object of the same type but don't want to free memory just to allocate it again. You can destroy the old object in place and construct a new one in place. (However, generally this is a bad idea.)
// pointer is destroyed because it goes out of scope,
// but not the object it pointed to. memory leak
if (1) {
Foo *myfoo = new Foo("foo");
}
// pointer is destroyed because it goes out of scope,
// object it points to is deleted. no memory leak
if(1) {
Foo *myfoo = new Foo("foo");
delete myfoo;
}
// no memory leak, object goes out of scope
if(1) {
Foo myfoo("foo");
}
Others have already addressed the other issues, so I'll just look at one point: do you ever want to manually delete an object.
The answer is yes. #DavidSchwartz gave one example, but it's a fairly unusual one. I'll give an example that's under the hood of what a lot of C++ programmers use all the time: std::vector (and std::deque, though it's not used quite as much).
As most people know, std::vector will allocate a larger block of memory when/if you add more items than its current allocation can hold. When it does this, however, it has a block of memory that's capable of holding more objects than are currently in the vector.
To manage that, what vector does under the covers is allocate raw memory via the Allocator object (which, unless you specify otherwise, means it uses ::operator new). Then, when you use (for example) push_back to add an item to the vector, internally the vector uses a placement new to create an item in the (previously) unused part of its memory space.
Now, what happens when/if you erase an item from the vector? It can't just use delete -- that would release its entire block of memory; it needs to destroy one object in that memory without destroying any others, or releasing any of the block of memory it controls (for example, if you erase 5 items from a vector, then immediately push_back 5 more items, it's guaranteed that the vector will not reallocate memory when you do so.
To do that, the vector directly destroys the objects in the memory by explicitly calling the destructor, not by using delete.
If, perchance, somebody else were to write a container using contiguous storage roughly like a vector does (or some variant of that, like std::deque really does), you'd almost certainly want to use the same technique.
Just for example, let's consider how you might write code for a circular ring-buffer.
#ifndef CBUFFER_H_INC
#define CBUFFER_H_INC
template <class T>
class circular_buffer {
T *data;
unsigned read_pos;
unsigned write_pos;
unsigned in_use;
const unsigned capacity;
public:
circular_buffer(unsigned size) :
data((T *)operator new(size * sizeof(T))),
read_pos(0),
write_pos(0),
in_use(0),
capacity(size)
{}
void push(T const &t) {
// ensure there's room in buffer:
if (in_use == capacity)
pop();
// construct copy of object in-place into buffer
new(&data[write_pos++]) T(t);
// keep pointer in bounds.
write_pos %= capacity;
++in_use;
}
// return oldest object in queue:
T front() {
return data[read_pos];
}
// remove oldest object from queue:
void pop() {
// destroy the object:
data[read_pos++].~T();
// keep pointer in bounds.
read_pos %= capacity;
--in_use;
}
~circular_buffer() {
// first destroy any content
while (in_use != 0)
pop();
// then release the buffer.
operator delete(data);
}
};
#endif
Unlike the standard containers, this uses operator new and operator delete directly. For real use, you probably do want to use an allocator class, but for the moment it would do more to distract than contribute (IMO, anyway).
When you create an object with new, you are responsible for calling delete. When you create an object with make_shared, the resulting shared_ptr is responsible for keeping count and calling delete when the use count goes to zero.
Going out of scope does mean leaving a block. This is when the destructor is called, assuming that the object was not allocated with new (i.e. it is a stack object).
About the only time when you need to call a destructor explicitly is when you allocate the object with a placement new.
1) Objects are not created 'via pointers'. There is a pointer that is assigned to any object you 'new'. Assuming this is what you mean, if you call 'delete' on the pointer, it will actually delete (and call the destructor on) the object the pointer dereferences. If you assign the pointer to another object there will be a memory leak; nothing in C++ will collect your garbage for you.
2) These are two separate questions. A variable goes out of scope when the stack frame it's declared in is popped off the stack. Usually this is when you leave a block. Objects in a heap never go out of scope, though their pointers on the stack may. Nothing in particular guarantees that a destructor of an object in a linked list will be called.
3) Not really. There may be Deep Magic that would suggest otherwise, but typically you want to match up your 'new' keywords with your 'delete' keywords, and put everything in your destructor necessary to make sure it properly cleans itself up. If you don't do this, be sure to comment the destructor with specific instructions to anyone using the class on how they should clean up that object's resources manually.
Pointers -- Regular pointers don't support RAII. Without an explicit delete, there will be garbage. Fortunately C++ has auto pointers that handle this for you!
Scope -- Think of when a variable becomes invisible to your program. Usually this is at the end of {block}, as you point out.
Manual destruction -- Never attempt this. Just let scope and RAII do the magic for you.
To give a detailed answer to question 3: yes, there are (rare) occasions when you might call the destructor explicitly, in particular as the counterpart to a placement new, as dasblinkenlight observes.
To give a concrete example of this:
#include <iostream>
#include <new>
struct Foo
{
Foo(int i_) : i(i_) {}
int i;
};
int main()
{
// Allocate a chunk of memory large enough to hold 5 Foo objects.
int n = 5;
char *chunk = static_cast<char*>(::operator new(sizeof(Foo) * n));
// Use placement new to construct Foo instances at the right places in the chunk.
for(int i=0; i<n; ++i)
{
new (chunk + i*sizeof(Foo)) Foo(i);
}
// Output the contents of each Foo instance and use an explicit destructor call to destroy it.
for(int i=0; i<n; ++i)
{
Foo *foo = reinterpret_cast<Foo*>(chunk + i*sizeof(Foo));
std::cout << foo->i << '\n';
foo->~Foo();
}
// Deallocate the original chunk of memory.
::operator delete(chunk);
return 0;
}
The purpose of this kind of thing is to decouple memory allocation from object construction.
Remember that Constructor of an object is called immediately after the memory is allocated for that object and whereas the destructor is called just before deallocating the memory of that object.
Whenever you use "new", that is, attach an address to a pointer, or to say, you claim space on the heap, you need to "delete" it.
1.yes, when you delete something, the destructor is called.
2.When the destructor of the linked list is called, it's objects' destructor is called. But if they are pointers, you need to delete them manually.
3.when the space is claimed by "new".
Yes, a destructor (a.k.a. dtor) is called when an object goes out of scope if it is on the stack or when you call delete on a pointer to an object.
If the pointer is deleted via delete then the dtor will be called. If you reassign the pointer without calling delete first, you will get a memory leak because the object still exists in memory somewhere. In the latter instance, the dtor is not called.
A good linked list implementation will call the dtor of all objects in the list when the list is being destroyed (because you either called some method to destory it or it went out of scope itself). This is implementation dependent.
I doubt it, but I wouldn't be surprised if there is some odd circumstance out there.
If the object is created not via a pointer(for example,A a1 = A();),the destructor is called when the object is destructed, always when the function where the object lies is finished.for example:
void func()
{
...
A a1 = A();
...
}//finish
the destructor is called when code is execused to line "finish".
If the object is created via a pointer(for example,A * a2 = new A();),the destructor is called when the pointer is deleted(delete a2;).If the point is not deleted by user explictly or given a new address before deleting it, the memory leak is occured. That is a bug.
In a linked list, if we use std::list<>, we needn't care about the desctructor or memory leak because std::list<> has finished all of these for us. In a linked list written by ourselves, we should write the desctructor and delete the pointer explictly.Otherwise, it will cause memory leak.
We rarely call a destructor manually. It is a function providing for the system.
Sorry for my poor English!
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).