I have a command pattern class with a pointer to another object (let's call it Duck). Its subclasses will use Duck, but to control and track when Duck is used (for debugging) I made Duck private and subclasses can only get it through a method getDuck();
class Command
{
private:
Duck* target;
public:
//Parametrized Constructor
Command(Duck* _target);
Duck* getDuck() { return target; }
...
};
I recently learned in Effective C++ by Scott Myers the horrors of returning a pointer. I tried just returning the dereferenced version, but that caused a copy of target to be returned. Should I (and is there a way to) simply return a Duck object instead of a pointer to it?
Conceptually, there are two kinds of pointers: owning and non-owning.
An owning pointer indicates that the holding object/function owns the allocation and is responsible for deleting the object.
A non-owning pointer is a "borrowed" object; the holding object/function does not own the object and is not responsible for cleaning it up.
Ideally, this manifests in the C++ type system since C++11 in the following ways:
std::unique_ptr<T>
is a unique-ownership pointer to a T
object. Exactly one object/function can own the allocation.std::shared_ptr<T>
is a shared-ownership pointer to a T
object. Many objects/functions share ownership of the allocation, and the target object is deleted only when all of them are done with it.T *
is a non-owning pointer. This is returned by functions to indicate that the caller does not own the object. The caller is not expected to delete the object; indeed, the caller may not delete it. The caller is expected not to use the pointer once the owning object/function destroys the target object.There is nothing inherently wrong with returning a raw pointer, though I would only return a pointer when the function needs to conditionally give access to an object it owns:
T *
: The function is returning a non-owning handle to an object, but it might not have an object so could return nullptr
. T *
is "optional, non-owning object handle."T &
: The function is returning a non-owning handle to an object, and it will always have such an object to return. T &
is "mandatory, non-owning object handle."Note that not all standard library facilities will respect these guidelines; indeed not all of them can! new T
must return a T *
because that's how it's defined to work. These are guidelines that you should follow in your application.