From my point of view, all you have to do is basically decide on a certain convention that you will use throughout your implementation. A good template for making your architecture allocator aware is to look on how this is achieved for the STL containers and try to design you data structures like them. If you look for example on the std::vector interface the second parameter to this container is always the Allocator type. The Allocator has to follow a certain interface that will allow easy replacing of the default allocator implementation by a custom one.
But coming back to code that you write: In a project that I work on we defined it like follows. For an object that is supposed to consume large amounts of memory we define a templated super class that allows to specify a custom allocator.
template<class AllocatedClass, typename Allocator=std::allocator<AllocatedClass> class AbstractMyClass { public: static void *operator new(size_t sz){ /*...*/ } static void operator delete(void *p){ /*...*/ } };
Now, if you define a subclass of this you would:
class MyClass : public AbstractMyClass<MyClass> { };
Thus the new object MyClass will use the specified allocator of the parent class. If you now implement you own allocator you can simply replace either the default template parameter in the super class or you can specify it explicitly in your sub-class.
Using this approach you are more or less safe in using a custom allocator at a later point in time.
new/new[]/delete/delete[]" - No, just overload these when the need arises, that's what overloading the allocation operators is for. "typedefs for containers and smart pointers" - rather use custom allocators when the need arises. Ok, typedefs could indeed help to not always have to specify the allocator type, but just specializing thestd::allocatoris a far better option if custom allocation is only needed for certain user-defined types.