Giuseppe Pes Giuseppe Pes - 2 months ago 7
C++ Question

Why isn't new implemented with template?

I am trying to instrument

new
with some additional information in order to track down a memory leak. I know, I can override a
new
operator globally, but I was surprise to discover that I cannot retrieve any information regarding the type of the object being allocated (Correct me if I am wrong). Clearly, it would be beneficial to have the type information when you decide to override the
new
operator.

For example, I've implemented a simple and generic version of
new
and
delete
using variadic template.

std::string to_readable_name(const char * str)
{
int status;
char *demangled_name = abi::__cxa_demangle(str, NULL, NULL, &status);
if(status == 0) {
std::string name(demangled_name);
std::free(demangled_name);
return name;
}
return "Unknown";
}

template <typename T, typename... Args>
T * generic_new(Args&&... args) throw (std::bad_alloc)
{
const std::size_t size = sizeof(T);
std::cout << "Allocating " << size << " bytes for " << to_readable_name(typeid(T).name()) << std::endl;
return new T(std::forward<Args>(args)...);
};

template<typename T>
void generic_delete(T* ptr)
{
const std::size_t size = sizeof(T);
std::cout << "Deleting " << size << " bytes for " << to_readable_name(typeid(T).name()) << std::endl;
delete ptr;
}

int main()
{
auto i = generic_new<int>(0);
std::cout << *i << std::endl;
generic_delete(i);

return 0;
}


My question is why hasn't
new
be implemented with template? This would allow developer to have information about the type of the object being allocated.

Thank you

Answer

Most questions about why C++ is designed how it is come down to two possibilities. Either The Design and Evolution of C++ gives a reason, or we can only speculate. I believe this falls into the latter category.

First of all, use of (and the ability to replace) operator new (both global and per-class) predates the addition of templates to the language. As such, it couldn't have been done with templates originally. Some parts of the library were switched to templates that hadn't been previously, but mostly where the benefits from doing so were extremely obvious.

Second, using a template with early template-capable compilers probably would have led to problems, especially for larger programs. The problem is that a function template isn't a function--it's a recipe for creating a function, so to speak. In other words, if it was implemented as a template, every allocator for every type would result in a separate function being instantiated. Current compilers (and linkers) are fairly good at merging those afterwards, but early ones mostly weren't. In a large system you could easily have had dozens or even hundreds of separate allocation functions created.

Finally, the template would typically still only be kind of an intermediate level between normal user code and something in the library that provides something at least roughly congruent to the current operator new and operator delete that talk to the OS (or hardware, or whatever) to figure out what pool to draw memory from, and (typically) sub-allocate pieces to the user code. Somewhere you need an (often fairly substantial) piece of code to create and manage a pool of memory. If this were handled directly in the template, it would (in practice) have to be implemented in a header, which would also lead to compile times that would probably have been fairly unacceptable on a 66 MHz Pentium or even that unbelievably fast 300 MHz DEC Alpha machine most of us could only dream about.

Comments