30

One of the thing that has been confusing for me while learning C++ (and Direct3D, but that some time ago) is when you should use a pointer member in a class. For example, I can use a non-pointer declaration:

private:
    SomeClass instance_;

Or I could use a pointer declaration

private:
   Someclass * instance_

And then use new() on it in the constructor.

I understand that if SomeClass could be derived from another class, a COM object or is an ABC then it should be a pointer. Are there any other guidelines that I should be aware of?

Dima
  • 38,860
  • 14
  • 75
  • 115
Extrakun
  • 19,057
  • 21
  • 82
  • 129

4 Answers4

27

A pointer has following advantages:

a) You can do a lazy initialization, that means to init / create the object only short before the first real usage.

b) The design: if you use pointers for members of an external class type, you can place a forward declaration above your class and thus don't need to include the headers of that types in your header - instead of that you include the third party headers in your .cpp - that has the advantage to reduce the compile time and prevents side effects by including too many other headers.

class ExtCamera;  // forward declaration to external class type in "ExtCamera.h"

class MyCamera {
public: 
  MyCamera() : m_pCamera(0) { }

  void init(const ExtCamera &cam);

private:
   ExtCamera  *m_pCamera;   // do not use it in inline code inside header!
};

c) A pointer can be deleted anytime - so you have more control about the livetime and can re-create an object - for example in case of a failure.

3DH
  • 1,461
  • 11
  • 11
  • 3
    For lazy initialization, I would recommend using `boost::optional` whenever possible. It's safer than pointer because you can't do arithmetic on it. – Pavel Minaev Jul 24 '09 at 03:55
  • 1
    But many (like me) don't use Boost - so this is a very platform and framework independent way ;-) ...I for example only use Qt :-) – 3DH Jul 24 '09 at 03:59
  • 1
    But those that don't use `boost` should :) – GManNickG Jul 24 '09 at 04:03
  • Is there a study on how much forward declaration helps to cut in compile time? Because using forward declaration, I cannot use reference in member function parameters too, such as Init(const QPointF&) -- forward declaration won't work for this. – Extrakun Jul 24 '09 at 04:04
  • I guess I will ask that question another time; for some reason it does not work for me... – Extrakun Jul 24 '09 at 04:20
  • I'm worried you accepted this. Not about rep, but that it *is* better to try and not to use pointers. – GManNickG Jul 24 '09 at 04:24
  • 1
    @Extrakun, make sure you are not trying to access any members of QPoint anywhere in that header file. – Dima Jul 24 '09 at 04:27
  • I wish I can accept more than one answer, because some of the post do contain reasons why I shouldn't use pointer members, but this one does at least explain the reason for pointer members. – Extrakun Jul 24 '09 at 04:28
  • 2
    You still can use forward declarations together with references - as far as you dont have any code in your header, which _uses_ (accesses) the references - so any declarations work, but not inline code. – 3DH Jul 24 '09 at 04:29
  • 1
    I managed to get forward declaration for reference working. I must have tried to access it somewhere in the .h file which is why it causing error. Thanks! – Extrakun Jul 24 '09 at 05:53
  • 1
    These are both silly reasons to use pointers in a class. Please de-select this as the best answer. – Martin York Jul 24 '09 at 06:03
  • 1
    Hi Martin, my intent is to find out 'when', not 'shouuld'. Naked pointers are of course dangerous. I will bear in the mind the risk of using naked pointers as members in a class. – Extrakun Jul 24 '09 at 10:39
  • @Martin: Your comment is not a perfect example of professional thinkink and acting. There are pros and contras - and the word is not just white and black. A professional developer should have the choice to use both methods and should know, why and why not. – 3DH Jul 26 '09 at 22:33
23

The advantages of using a pointer are outlined by 3DH: lazy initialization, reduction in header dependencies, and control over the lifetime of the object.

The are also disadvantages. When you have a pointer data member, you probably have to write your own copy constructor and assignment operator, to make sure that a copy of the object is created properly. Of course, you also must remember to delete the object in the destructor. Also, if you add a pointer data member to an existing class, you must remember to update the copy constructor and operator=. In short, having a pointer data member is more work for you.

Another disadvantage is really the flip side of the control over the lifetime of the object pointed to by the pointer. Non-pointer data members are destroyed automagically when the object is destroyed, meaning that you can always be sure that they exist as long as the object exists. With the pointer, you have to check for it being nullptr, meaning also that you have to make sure to set it to nullptr whenever it doesn't point to anything. Having to deal with all this may easily lead to bugs.

Finally, accessing non-pointer members is likely to be faster, because they are contiguous in memory. On the other hand, accessing pointer data member pointing to an object allocated on the heap is likely to cause a cache miss, making it slower.

There is no single answer to your question. You have to look at your design, and decide whether the advantages of pointer data members outweigh the additional headache. If reducing compile time and header dependencies is important, use the pimpl idiom. If your data member may not be necessary for your object in certain cases, use a pointer, and allocate it when needed. If these do not sound like compelling reasons, and you do not want to do extra work, then do not use a pointer.

If lazy initialization and the reduction of header dependencies are important, then you should first consider using a smart pointer, like std::unique_ptr or std::shared_ptr, instead of a raw pointer. Smart pointers save you from many of the headaches of using raw pointers described above.

Of course, there are still caveats. std::unique_ptr cleans up after itself, so you do not need to add or modify the destructor of your class. However, it is non-copiable, so having a unique pointer as a data member makes your class non-copiable as well.

With std::shared_ptr, you do not have to worry about the destructor or copying or assignment. However, the shared pointer incurs a performance penalty for reference counting.

Dima
  • 38,860
  • 14
  • 75
  • 115
12

Allocate it on the stack if you can, from the free-store if you have to. There is a similar question here, where you will find all the "why's".

The reason you see lots of pointer usage when it comes to games and stuff is because DirectX is a COM interface, and in honesty, most games programmers from back in the day aren't really C++ programmers, they are C-with-classes programmers, and in C pointer usage is very common.

Community
  • 1
  • 1
GManNickG
  • 494,350
  • 52
  • 494
  • 543
4

Another reason to use pointers would be dynamic binding. If you have a base class with a virtual method and some derived classes, you can only get dynamic binding using pointers.