Avoid using plain new or other raw unmanaged allocation directly.
The Joys of Raw Pointer-Agnostic Programming
So following Herb Sutter, we ideally never want to see a pointer
because of direct allocation at all. Prior to
C++11 it was common to
add a static
create factory method to each function. Which means a
lot of repetitive typing as we need to forward all arguments to the
constructor (which is private here to disable the stack for this
object). And we still have an explicit
new in the code here. Check
std::make_shared which is template
functions that yields a
std::share_ptr to the object. Thus, we how
have a neat generic factory function.
std::make_unique which is the same thing for a
we are limited to
C++11 you can emulate it). The best thing
about it: these generic factory functions completely hide the
invocation. Check out the code now:
Excellent! Now we have everything to completely erase
completely from our memories, correct?
The Woes of Raw Pointer-Agnostic Programming
And here’s the sad news of this article: No, the generic factory functions are not as universal as they seem.
C++03 example we wanted a private constructor for reasons of
lifetime clarity (Good Thing TM).
std::make_unique<Object> does not
Object(), therefore you get a compile error. Now you have three
You grant friendship to a specialized
std::make_unique<Object>. A little bit awkward, but friendship with a generic factory does not violate encapsulation. Okay, but what if
std::make_unique<Object>delegates construction (see Q2 in N3588)to other functions as an implementation detail? And library developers really like to do that for various reasons. For your solution at hand, this means: Game over. This is not portable.
You refrain from using a generic factory method and use a static factory method like
createUnique(). This works fine unless you find yourself using a template function that calls
std::make_unique<Object>. If you write client code using this template function, this essentially means go to item 1 (i.e., game over). If you own the template function, you can awkwardly code around the problem.
You make the constructor
public. That means the generic factory function has forced a design choice upon your code. I hate it, when generic factory functions do that…
Okay, we grind our teeth and grant
public visibility to the
Object. Let’s go back to our previous
Object also inherited an implementation detail (called
ImplDetail). I find myself using private inheritance quite often
when passing handlers to object who receive messages asynchronously.
What does private inheritance mean for
std::make_unique? Here is an
Depending on your compiler, you receive an error message like:
error: ‘Interface’ is an inaccessible base of ‘Implementer’
In other words since
make_unique<ClientObject> does not know that
Implementer implements an
Interface. For this issue, we do not even have
friendship to help us out. Once more, the generic factory functions
will dictate a design decision to you. The entire world will need to
Implements is an
My enthusiasm for the generic factory functions
std::make_shared has declined. Previously, I thought that these two
functions may be the key to future devoid of any raw pointers. I am
curious to see whether and how the issues described above will be
addressed by the committee.