Dean
Dean

Reputation: 6958

Overriding global new/delete: do I still need a stl custom allocator for containers?

In order to track our memory usage and display some runtime statistics to the user (in a performant way) I'm overriding global new/delete (with a #define in a header - adding that header on top of every source file where we need to allocate/deallocate memory is going to ensure we can track all allocations going on).

I have two questions at this point since it's a multi-platform C++ codebase:

Upvotes: 2

Views: 1289

Answers (2)

Alex Vergara
Alex Vergara

Reputation: 2278

First question: Yes

  • The details of how operator new is implemented are property of a particular implementation of standard library - not even a compiler or operation system. All of them, at least, the three big ones, (CLang, GCC and MSVC) are using malloc() within operator new, because it just makes a life of library developer so much easier. So, yes, you will need to override the malloc/free/calloc/realloc.

Second question: No

  • std::vector uses std::allocator by default, and std::allocator is required to use global operator new, that is, ::operator new(size_t) to obtain the memory. However, it isn't required to call it exactly once per call to allocator::allocate.

  • If you replace global operator new, then vector will use it, although not necessarily in a way that really allows your implementation to manage memory "efficiently". Any special tricks you want to use could, in principle, be made completely irrelevant by std::allocator grabbing memory in 10MB chunks and sub-allocating.

You are fighting against a legacy old codebase. Any pure text replacement, like #define preprocessor directives are really discouraged (luckily, some day C++ will get rid out of preprocessor), but, in your concrete case, it could be a viable approach.

Upvotes: 5

A M
A M

Reputation: 15275

If containers, like for example std::vector use the default allocater std::allocater as described here, then the std::allocaterwill call the global new function in its allocatefunction, as described here.

Allocates n * sizeof(T) bytes of uninitialized storage by calling ::operator new(std::size_t) or ::operator new(std::size_t, std::align_val_t) (since C++17)

So, it will call the global new and if you override it then your implementation will be called. Please see the below example:

#include <iostream>
#include <iostream>
#include <vector>
#include <stdlib.h>
 
using namespace std;
void * operator new(size_t size)
{
    cout << "New operator overloading " << endl;
    void * p = malloc(size);
    return p;
}

int main()
{
    std::vector<int> v{};
    v.resize(50);
    v.resize(1500);
}

Upvotes: 1

Related Questions