views:

233

answers:

11

Hi,

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.

Regards

Mark

+10  A: 

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)

jalf
On the other hand, PIMPL is all about cutting down the dependencies by introducing a layer of indirection in the visibility.
Matthieu M.
+5  A: 

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.

Bart van Ingen Schenau
+1  A: 

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.

Als
+2  A: 

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
Shmoopty
+2  A: 

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.

chvor
+1  A: 

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)

ur
+9  A: 

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)

Justin
The big downside to this in larger projects is it forces a #include of the header where MyOtherClass is declared. This can quickly lead to very slow compilation times. If you use a (smart) pointer, you can get away with a forward declaration.
Ben
@Ben +1 yes - i failed to mention intermodule dependencies and abstraction of them in my post. this is a very important reason to favor dynamically allocated members in some cases.
Justin
+2  A: 

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
Timo
+3  A: 

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!

Wolfgang Plaschg
I don't find thinking in terms of heap/stack very usefull (especially since neither are really defined by the standard). I think of objects in terms of their lifespan in relation to the containing block. An object with a scoped life should be an object. An object that has a dynamic lifespan should be a pointer (stored in a smart pointer). The only different between a member variable and a function variable is their scope. A member variables lifespan is relative to its scope the object that it resides in. While a function variables is relative to its scope the function (or block).
Martin York
That's definitly true, but the question was where the objects are stored in memory, which is useful to sort things out in your head.
Wolfgang Plaschg
A: 

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.

andreas buykx
A: 

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).

Alexandre C.