Consider the following code:
class A
{
B* b; // an A object owns a B object
A() : b(NULL) { } // we don't know what b will be when constructing A
void calledVeryOften(…)
{
if (b)
delete b;
b = new B(param1, param2, param3, param4);
}
};
My goal: I need to maximize performance, which, in this case, means minimizing the amount of memory allocations.
The obvious thing to do here is to change B* b;
to B b;
. I see two problems with this approach:
- I need to initialize
b
in the constructor. Since I don't know whatb
will be, this means I need to pass dummy values to B's constructor. Which, IMO, is ugly. - In
calledVeryOften()
, I'll have to do something like this:b = B(…)
, which is wrong for two reasons:- The destructor of
b
won't be called. - A temporary instance of B will be constructed, then copied into
b
, then the destructor of the temporary instance will be called. The copy and the destructor call could be avoided. Worse, calling the destructor could very well result in undesired behavior.
- The destructor of
So what solutions do I have to avoid using new
? Please keep in mind that:
- I only have control over A. I don't have control over B, and I don't have control over the users of A.
- I want to keep the code as clean and readable as possible.
Just have a pile of previously used Bs, and re-use them.
If
B
correctly implements its copy assignment operator thenb = B(...)
should not call any destructor onb
. It is the most obvious solution to your problem.If, however,
B
cannot be appropriately 'default' initialized you could do something like this. I would only recommend this approach as a last resort as it is very hard to get safe. Untested, and very probably with corner case exception bugs:I'd go with boost::scoped_ptr here:
No need for hand-crafted destructor,
A
is non-copyable, as it should be in your original code, not to leak memory on copy/assignment.I'd suggest to re-think the design though if you need to re-allocate some inner state object very often. Look into Flyweight and State patterns.
How about allocating the memory for B once (or for it's biggest possible variant) and using placement new?
A would store
char memB[sizeof(BiggestB)];
and aB*
. Sure, you'd need to manually call the destructors, but no memory would be allocated/deallocated.