When to use pointers and when not to?
I'm used to doing Java programming, where you never really have to think about pointers when programming. However, at the moment I'm writing a program in C++. When making classes that have members of other classes, when should I use pointers and when should I not? For example, when would I want to do this:
class Foo {
Bar b;
}
As opposed to this:
class Foo {
Bar* b;
}
Start by avoiding pointers.
Use them when:
- You want to use the Pimpl idiom, or an abstract factory.
- The
Bar
instance is actually managed by some other part of your program, whereas theFoo
class just needs to be able to access it. - You want to postpone the construction of the
Bar
object (i.e., you want to create it after constructingFoo
). - In your business logic, the
Bar
object may not exist at all; you would usenull
also in Java. However, check out boost::optional as well. -
Bar
is actually a base class, and you need the instance to be polymorphic. - You happen to be using a toolkit that prefers to present GUI widgets as pointers. Examples could include (but are certainly not limited to) wxWidgets and GLUI.
In any of these cases (*), start by using a smart pointer, such as boost::shared_ptr. Otherwise, you are likely to forget to deallocate the memory, sooner or later. Once you know what you are doing, consider case-by-case what pointer type is best.
(*) any case – except, probably, the bullet regarding GUI widgets; in this case, your toolkit would most probably manage the resources for you as well
class Foo {
Bar b;
}
b is contained in Foo. If the Foo object ends lifetime, b automatically ends lifetime too. This is what models composition. b above denotes the object itself, not just a pointer to it like in Java. Therefor, if b goes out of scope, the object will end lifetime.
class Foo {
Bar * b;
}
Here, the object b points to is used by or referenced by the Foo object. If the Foo object ends lifetime, the object b points to may continue to live, depending on circumstances. This can be used to model aggregation and general relationship. The object may be shared with other Foo objects for example.
Pointers are roughly what references are in Java. They can also point to nothing. If a pointer points to nothing, it's a null pointer.
Similar to pointers are references. References in C++ must be initialized and can only point to one (valid) object, for which the reference was initialized. A reference therefor cannot hold value which could mean "nothing" like null
in Java.
In the first example memory for the Bar object will be allocated automatically when you construct the Foo object. In the second case you need to allocate the memory yourself. So you must call:
Foo *foo = new Foo();
foo->b = new Bar();
This may be desirable if the Bar object is large and you don't want to bundle it with the Foo object. It is also desirable when the construction of the Bar object is independent of the creation of Foo object. In this case the b object is "injected" into foo:
Foo *foo = new Foo();
foo->b = b_ptr;
where b_ptr is constructed somewhere else and a pointer is passed to foo.
For smaller objects it is dangerous, as you may forget to allocate the memory.
Both are OK under different conditions. For example, if you know how to construct b when an object of class Foo is constructed, the first is OK. But if you don't, the only choice is to use the second.
You need to do some assembly programming and understand the memory layout well. C is just a crossplatform assembly, unlike Java or other languages. To use it properly, one should understand low level details.
All comments made are valid, but for individuals like you, who jump from high level languages to C, having this sort of experience would be more than beneficial. With proper understanding, you would not ask questions like that anymore.