My following question is on memory management. I have for example an int variable not allocated dynamically in a class, let's say invar1. And I'm passing the memory address of this int to another classes constructor. That class does this:
class ex1{
ex1(int* p_intvar1)
{
ptoint = p_intvar1;
}
int* ptoint;
};
Should I delete ptoint? Because it has the address of an undynamically allocated int, I thought I don't need to delete it.
And again I declare an object to a class with new operator:
objtoclass = new ex1();
And I pass this to another class:
class ex2{
ex2(ex1* p_obj)
{
obj = p_obj;
}
ex1* obj;
};
Should I delete obj when I'm already deleting objtoclass?
Thanks!
Because it has the address of an undynamically allocated int I thought I don't need to delete it.
Correct.
Should I delete obj when I'm already deleting objtoclass?
No.
Recall that you're not actually deleting pointers; you're using pointers to delete the thing they point to. As such, if you wrote both delete obj and delete objtoclass, because both pointers point to the same object, you'd be deleting that object twice.
I would caution you that this is a very easy mistake to make with your ex2 class, in which the ownership semantics of that pointed-to object are not entirely clear. You might consider using a smart pointer implementation to remove risk.
just an appendix to the other answers
You can get rid of raw pointers and forget about memory management with the help of smart pointers (shared_ptr, unique_ptr).
The smart pointer is responsible for releasing the memory when it goes out of scope.
Here is an example:
#include <iostream>
#include <memory>
class ex1{
public:
ex1(std::shared_ptr<int> p_intvar1)
{
ptoint = p_intvar1;
std::cout << __func__ << std::endl;
}
~ex1()
{
std::cout << __func__ << std::endl;
}
private:
std::shared_ptr<int> ptoint;
};
int main()
{
std::shared_ptr<int> pi(new int(42));
std::shared_ptr<ex1> objtoclass(new ex1(pi));
/*
* when the main function returns, these smart pointers will go
* go out of scope and delete the dynamically allocated memory
*/
return 0;
}
Output:
ex1
~ex1
Should I delete obj when I'm already deleting objtoclass?
Well you could but mind that deleting the same object twice is undefined behaviour and should be avoided. This can happen for example if you have two pointers for example pointing at same object, and you delete the original object using one pointer - then you should not delete that memory using another pointer also. In your situation you might as well end up with two pointers pointing to the same object.
In general, to build a class which manages memory internally (like you do seemingly), isn't trivial and you have to account for things like rule of three, etc.
Regarding that one should delete dynamically allocated memory you are right. You should not delete memory if it was not allocated dynamically.
PS. In order to avoid complications like above you can use smart pointers.
You don't currently delete this int, or show where it's allocated. If neither object is supposed to own its parameter, I'd write
struct ex1 {
ex1(int &i_) : i(i_) {}
int &i; // reference implies no ownership
};
struct ex2 {
ex2(ex1 &e_) : e(e_) {}
ex1 &e; // reference implies no ownership
};
int i = 42;
ex1 a(i);
ex2 b(a);
If either argument is supposed to be owned by the new object, pass it as a unique_ptr. If either argument is supposed to be shared, use shared_ptr. I'd generally prefer any of these (reference or smart pointer) to raw pointers, because they give more information about your intentions.
In general, to make these decisions,
Should I delete ptoint?
is the wrong question. First consider things at a slightly higher level:
what does this int represent in your program?
who, if anyone, owns it?
how long is it supposed to live, compared to these classes that use it?
and then see how the answer falls out naturally for these examples:
this int is an I/O mapped control register.
In this case it wasn't created with new (it exists outside your whole program), and therefore you certainly shouldn't delete it. It should probably also be marked volatile, but that doesn't affect lifetime.
Maybe something outside your class mapped the address and should also unmap it, which is loosely analogous to (de)allocating it, or maybe it's simply a well-known address.
this int is a global logging level.
In this case it presumably has either static lifetime, in which case no-one owns it, it was not explicitly allocated and therefore should not be explicitly de-allocated
or, it's owned by a logger object/singleton/mock/whatever, and that object is responsible for deallocating it if necessary
this int is being explicitly given to your object to own
In this case, it's good practice to make that obvious, eg.
ex1::ex1(std::unique_ptr<int> &&p) : m_p(std::move(p)) {}
Note that making your local data member a unique_ptr or similar, also takes care of the lifetime automatically with no effort on your part.
this int is being given to your object to use, but other objects may also be using it, and it isn't obvious which order they will finish in.
Use a shared_ptr<int> instead of unique_ptr to describe this relationship. Again, the smart pointer will manage the lifetime for you.
In general, if you can encode the ownership and lifetime information in the type, you don't need to remember where to manually allocate and deallocate things. This is much clearer and safer.
If you can't encode that information in the type, you can at least be clear about your intentions: the fact that you ask about deallocation without mentioning lifetime or ownership, suggests you're working at the wrong level of abstraction.
Because it has the address of an undynamically allocated int, I
thought I don't need to delete it.
That is correct. Simply do not delete it.
The second part of your question was about dynamically allocated memory. Here you have to think a little more and make some decisions.
Lets say that your class called ex1 receives a raw pointer in its constructor for a memory that was dynamically allocated outside the class.
You, as the designer of the class, have to decide if this constructor "takes the ownership" of this pointer or not. If it does, then ex1 is responsible for deleting its memory and you should do it probably on the class destructor:
class ex1 {
public:
/**
* Warning: This constructor takes the ownership of p_intvar1,
* which means you must not delete it somewhere else.
*/
ex1(int* p_intvar1)
{
ptoint = p_intvar1;
}
~ex1()
{
delete ptoint;
}
int* ptoint;
};
However, this is generally a bad design decision. You have to root for the user of this class read the commentary on the constructor and remember to not delete the memory allocated somewhere outside class ex1.
A method (or a constructor) that receives a pointer and takes its ownership is called "sink".
Someone would use this class like:
int* myInteger = new int(1);
ex1 obj(myInteger); // sink: obj takes the ownership of myInteger
// never delete myInteger outside ex1
Another approach is to say your class ex1 does not take the ownership, and whoever allocates memory for that pointer is the responsible for deleting it. Class ex1 must not delete anything on its destructor, and it should be used like this:
int* myInteger = new int(1);
ex1 obj(myInteger);
// use obj here
delete myInteger; // remeber to delete myInteger
Again, the user of your class must read some documentation in order to know that he is the responsible for deleting the stuff.
You have to choose between these two design decisions if you do not use modern C++.
In modern C++ (C++ 11 and 14) you can make things explicit in the code (i.e., do not have to rely only on code documentation).
First, in modern C++ you avoid using raw pointers. You have to choose between two kinds of "smart pointers": unique_ptr or shared_ptr. The difference between them is about ownership.
As their names say, an unique pointer is owned by only one guy, while a shared pointer can be owned by one or more (the ownership is shared).
An unique pointer (std::unique_ptr) cannot be copied, only "moved" from one place to another. If a class has an unique pointer as attribute, it is explicit that this class has the ownership of that pointer. If a method receives an unique pointer as copy, it is explicit that it is a "sink" method (takes the ownership of the pointer).
Your class ex1 could be written like this:
class ex1 {
public:
ex1(std::unique_ptr<int> p_intvar1)
{
ptoint = std::move(p_intvar1);
}
std::unique_ptr<int> ptoint;
};
The user of this class should use it like:
auto myInteger = std::make_unique<int>(1);
ex1 obj(std::move(myInteger)); // sink
// here, myInteger is nullptr (it was moved to ex1 constructor)
If you forget to do "std::move" in the code above, the compiler will generate an error telling you that unique_ptr is not copyable.
Also note that you never have to delete memory explicitly. Smart pointers handle that for you.
Related
In general, I always pass pointers through functions of any objects I create; if I need something done to an object, I would pass it by pointer rather than by reference. That's just a programming habit which some might describe as miniscule; but this is where I have to ask by example:
class someObject
{
public:
someObject();
~someObject();
void do(const char* smth)
{
cout << smth << endl;
}
private:
};
class doObject
{
public:
doObject();
~doObject();
void takeObject(someObject *so)
{
pObject = so;
so->do("Hi");
}
private:
someObject *pObject;
}
And in main.cpp:
int main()
{
someObject *so = new someObject();
so->do();
doObject *do = new doObject();
do->takeObject(so);
delete so;
delete do;
}
Should memory be allocated to doObject::pObject BEFORE it is assigned the pointer parameter so of type someObject?
If pObject is assigned the foresaid parameter, should it be deleted; e.g. delete pObject?
In main.cpp someObject is deleted BEFORE doObject is. This is vital to understand because doObject has an assignment of someObject called pObject. Deleting someObject before doObject means there's a dangling pointer which implies any actions on it would produce a segmentation fault.
If I delete doObject first in main.cpp, does that also delete pObject AS WELL AS 'so' of type someObject? After all, they are linked.
If I create a new class that also a function which also requires a parameter of someObject, does that mean pObject no longer points to 'so'? Should I instead use a shared pointer so that it's possible for both classes to be able to point to 'so' and change the object as necessary?
How can the code be improved? Should I consider the use of smart pointers to ensure that I do not delete an object more than once in various parts of a program?
Yes, the question is rather complex; but that's what you get with pointers!
Should memory be allocated to doObject::pObject BEFORE it is assigned the pointer parameter so of type someObject?
Memory is allocated in main and a pointer to that memory is assigned to so. The member variable pObject will just point at the same object as so does. So memory is allocated before you assigne the member pointer variable.
If pObject is assigned the foresaid parameter, should it be deleted; e.g. delete pObject?
Someone must delete the object pointed at to not get a memory leak. Either someone does it or the ownership is shared. You decide if you transfer the ownership when you pass the pointer to another function, or not. Being consistent is the key and using smart pointers is a help.
In main.cpp someObject is deleted BEFORE doObject is. This is vital to understand because doObject has an assignment of someObject called pObject. Deleting someObject before doObject means there's a dangling pointer which implies any actions on it would produce a segmentation fault.
If you allocate dynamic memory, always deallocate in reverse allocation order to prevent dangling pointers.
If I delete doObject first in main.cpp, does that also delete pObject AS WELL AS 'so' of type someObject? After all, they are linked.
No. If the doObject destructor had done delete pObject;, then it would.
If I create a new class that also a function which also requires a parameter of someObject, does that mean pObject no longer points to 'so'? Should I instead use a shared pointer so that it's possible for both classes to be able to point to 'so' and change the object as necessary?
pObject doesn't point at so, it points at the same dynamically allocated object as so does. Any number of pointers to that object can exist in any number of classes, but it's your resonsibility to make sure that after the object is deleed, no holder of a pointer to it uses that pointer. That's why it's important to dlete objects in the correct order.
How can the code be improved? Should I consider the use of smart pointers to ensure that I do not delete an object more than once in various parts of a program?
Yes, smart pointers if you want to share the ownership (shared_ptr) or ensure there's just one owner (unique_ptr), or have the guideline that a pointer parameter is only referring to an instance, never owning.
Also use automatic instances where possible instead of dynamic.
How can the code be improved? Should I consider the use of smart pointers to ensure that I do not delete an object more than once in various parts of a program?
I'd recommend learning manual memory management first and once you've mastered it, then start using smart pointers. But of course you can jump straight into smart pointers if you think you don't need to know manual memory management.
So as to explain about pointers and references in this question I wrote this code.
MyClass& MyClass::MyInstance()
{
static MyClass & myLocalVariable = * new MyClass(/*parameters*/);
return myLocalVariable ;
}
one of the comments, by a really impressive high reputation SO user, simply states:
*new is always wrong. ALWAYS.
It is the first time I'm told about this: Is it a famous coding standard we all should know about ? What are the reasons behind ?
I'm normally pragmatic, however this is too much even for me!
static MyClass & myLocalVariable = * new MyClass(/*parameters*/);
Seriously? Why not simply:
static MyClass myLocalVariable{/*parameters*/};
The most obvious reason is that if you don't keep a copy of the pointer which new returned, you're not likely to ever call delete on it.
On a more human level, it will make people reading your code think less of you, and that's never a good thing either.
I believe the stated user meant that allocating a static object using new is dangerous as the memory will most probably be leaked. Even more importantly your variable is not a pointer but a reference so the chance that you never free the memory returned by new is even greater(how often do you delete the address of a reference?).
THE problem is more than just useless allocations.
If nobody calls delete on it, it won't be deleted. Sure, the memory will be released when the program ends but its destructor doesn't get called.
Compare the output of using Get() and Get2() in the code below:
#include <iostream>
struct A
{
~A(){std::cout << "Deleted\n";}
};
A& Get()
{
static A & a = *new A;
return a;
}
A& Get2()
{
static A a;
return a;
}
int main()
{
//Case 1
Get();
//Case 2
Get2();
}
The output of this program is nothing when calling Get and Deleted when calling Get2.
In other words, resources with nontrivial destructors (commit-on-close file handle for example) will not be destroyed properly at program termination in case 1, but will in case 2.
The problem is that a raw new does not specify ownership. If I new up an object and return it, who owns it? Does the creating function/object own it, or does the calling function? If you return smart pointers (std::shared_ptr and std::unique_ptr) you are specifying ownership.
Not specifying ownership is one of the easiest ways to leak memory. I have the hardest time, even with professional programmers, getting people to understand ownership and work with it. This is mostly prevented by using good types (smart pointers) that specify ownership, just by existing.
type* function(); // Unspecified ownership.
// Must be well documented and all users must read
// and follow the documentation.
std::unique_ptr<type> function(); // Calling function owns returned pointer.
// Single ownership.
std::shared_ptr<type> function(); // Calling function owns returned pointer.
// Shared ownership. Can have multiple owners.
std::weak_ptr<type> function(); // Calling function references returned pointer.
// Must lock pointer to get owned object, if not deleted.
// Shared ownership. Can have multiple owners.
These different types of pointers express ownership just by existing unlike raw pointers.
As for new always being wrong. That is an overbroad generalization. std::shared_ptr is created using the global function std::make_shared. As of C++11 there is no std::make_unique, but that will be fixed in C++14. The only way to create a std::unique_ptr is to use new and immediately assign the pointer to a std::unique_ptr.
There are also places where you would want a raw pointer and to manually use new and delete, but they tend to be very low level and most programmers will rarely encounter them.
What really has me cringing about your code is not that you are using new but that you are dereferencing the pointer and assigning it to a reference. It would be almost impossible to guarantee that the destructor will ever be called. It also tends to leak memory, though in the case of assigning to a static variable it will be deallocated at program termination so you aren't really looking at memory leaking.
MyClass& MyClass::MyInstance()
{
static MyClass & myLocalVariable = * new MyClass(/*parameters*/);
return myLocalVariable ;
}
I would prefer to create to have the static variable be by value than by reference. This prevents putting the object on the heap. Depending on MyClass is could also allow the object to be mapped to memory from the executable without having to run any code to initialize it.
MyClass& MyClass::MyInstance()
{
static MyClass myLocalVariable(/*parameters*/);
return myLocalVariable ;
}
struct Temp
{
CString one;
CString two;
};
class Foo
{
public:
Temp obj;
void somewhere();
}
void Foo::somewhere()
{
void* pData = static_cast<void*>(&obj);
OwnMethod(pData); // void OwnMethod(void*);
}
The question is:
Should I create obj on heap or this situation isn't dangerous (passing local class objects pointer)?
If OwnMethod(pData) stores the pointer somwhere for later use, that later use is not possible anymore, once the object on which Foo::somewhere() is called is destroyed.
If OwnMethod(pData) only access the pointed to data, you are safe.
The member variable will last as long as the Foo object, so the pointer will be valid during the call to OwnMethod.
If that function stores a copy of the pointer somewhere, and something else uses that pointer later, then there is a danger that it might be accessed after the Foo (and therefore the pointer's target) have been destroyed. There are various ways to prevent that; as you say, one is to dynamically allocate the object, and then transfer or share ownership when it's passed to OwnMethod. Smart pointers, such as std::unique_ptr and std::shared_ptr, are a very good way to track ownership of dynamic objects.
Wow, a lot of issues.
A complex object should't be passed to anything taking a void*.
Who wrote OwnMethod?
Why doesn't it take a pointer of type Foo*?
In fact why doesn't it take a reference of type Foo&?
If OwnMethod() may be required to accept objects of several different types then it should take a base class pointer or reference and use polymorphism.
However as far as the lifetime arguments go - obj will exist as long as the wrapping class does, so if the pointer is not used beyond the scope of OwnMethod this is ok. If OwnMethod causes the pointer to be stored elsewhere beyond Foo's lifetime then you have an issue, and maybe obj should be allocated on the heap. (And it might not even be appropriate for it to be a member of Foo at all.)
I am not experienced in handling of the memory in a C++ program, so I would like a piece of advice in that case:
I want to create a new Object in a function in a class which is essential till the end of the program. As far as I am concerned, if I use the operator new, I should sometimes delete it. Taking into account that it must be initialized inside a class, when and how must I finally delete it?
I suggest the smart pointer idiom
#include <memory>
struct X
{
void foo() { }
};
std::share_ptr<X> makeX() // could also be a class member of course
{
return std::make_shared<X>();
}
int main()
{
std::share_ptr<X> stayaround = makeX();
// can just be used like an ordinary pointer:
stayaround->foo();
// auto-deletes <sup>1</sup>
}
If the pointer is truly a static variable, you can substitute a unique_ptr (which works similarly, but passes ownership on assignment; this means that the pointer doesn't have to keep a reference count)
Note To learn more about C++ smart pointers in general, see smart pointers (boost) explained
Note If you don't have the TR1/C++0x support for this, you can just use Boost Smartpointer
1 unless you are leaking copies of the shared_ptr itself; that would be some strange use of smart pointers previously unseen :)
Edit: Using some sort of smart pointer is often a good idea, but I believe it is still essential to have a solid understanding of manual memory management in C++.
If you want an object in a class to persist until the end of the program, you can simply make it a member variable. From what you've said, there's nothing to suggest you need to use new or delete here, just make it an automatic variable. If you did want to use new and delete for practice, you should read up on constructors and destructors for a class (you can and will use new and delete outside of classes, but I'm trying to keep this relevant to your question). Here's one I prepared earlier:
class Foo
{
public:
Foo(); // Default constructor.
~Foo(); // Destructor.
private:
int *member;
}
Foo::Foo() // Default constructor definition.
{
member = new int; // Creating a new int on the heap.
}
Foo::~Foo() // Destructor.
{
delete member; // Free up the memory that was allocated in the constructor.
}
This is a simple example, but it will hopefully help you out. Note that the variable will only persist as long as the object is alive. If the object is destroyed or goes out of scope, the destructor will be called and the memory will be freed.
You can use the smart pointer as suggested by Sehe or you can create a static object in the function and return a reference to it. You need not explictly delete the object, when the process terminates the object will be deleted. Like:
struct X {};
X& makeX() // could also be a class member of course
{
static X x;
return x;
}
int main()
{
X& stayaround = makeX();
}
On most operating systems (in particular Linux), if you allocate an object pointer with new Object, and don't bother delete-ing because you'll need it till the program ends, no harm is really done. There is some memory leak inside your program (you can use valgrind to hunt such leaks) but the kernel will release all the memory used by a process when it has ended.
A better alternative is to have a singleton class for the application data, like e.g. QApplication in Qt, ahd construct a single instance in that class early in your main, and have that class contain a smart or dumb pointer to your Object. The destructor should delete that object.
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).