0

I would like to define some re-definitions of the new and delete operators in c++ to play a bit around and track memory allocations / freeing, something in this kind:

#include <iostream>
#include <vector>

void* operator new(std::size_t n) {
    std::cout << "[Allocate " << n << " bytes]";
    void * ptr_out = malloc(n);
    std::cout << " at addr " << ptr_out << std::endl;
    return ptr_out; 
}

void operator delete(void* p) throw() {
    std::cout << "[Free 1  byte] at addr " << p << std::endl;
    free(p);
}

void operator delete(void* p, std::size_t nbr_bytes) throw() {
    std::cout << "[Free " << nbr_bytes << " bytes] at addr " << p << std::endl;
    free(p);
}

int main()
{
    std::cout << "small vector" << std::endl;
    std::vector<int> vec_1 {1, 2, 3, 4};
}

I am able to intercept the memory allocation (new) well, however I do not manage to intercept the memory freeing (delete) in such a way as to show that a whole memory block is released, i.e. I get:

small vector
[Allocate 16 bytes] at addr 0x55b1c5d84280
[Free 1  byte] at addr 0x55b1c5d84280

while really I would want to show that the program released the full 16 bytes of the vector when the program returns.

Any idea if / how I can do this, i.e. print the following instead?

small vector
[Allocate 16 bytes] at addr 0x55b1c5d84280
[Free 16  bytes] at addr 0x55b1c5d84280
Zorglub29
  • 6,979
  • 6
  • 20
  • 37
  • 1
    You will need your own bookkeeping because there is no way to get the size of an allocation from a `void *` – user4581301 Dec 01 '20 at 21:05
  • You might need to create a custom class in which you can do the above, plus track the exact size of it's content in memory... – Jean-Benoit Harvey Dec 01 '20 at 21:07
  • I was wondering when digging on this, how does this work in practice when deleting a block of memory? Is it enough to say "delete block" and somehow something knows how big the block is, or is it an order to "delete N bytes starting from this location", in which case I should be able to capture the N? – Zorglub29 Dec 01 '20 at 21:15
  • 1
    The implementation keeps the size somewhere however it is an implementation defined behavior. – drescherjm Dec 01 '20 at 21:16
  • Mmmh, this is not too clear to me. That shows there is much to learn as soon as one looks under the hood ^^ :) – Zorglub29 Dec 01 '20 at 21:17
  • 2
    Related to msvc: [https://stackoverflow.com/questions/4955399/visual-studio-2010-c-get-size-of-memory-block-allocated-by-malloc](https://stackoverflow.com/questions/4955399/visual-studio-2010-c-get-size-of-memory-block-allocated-by-malloc) – drescherjm Dec 01 '20 at 21:21
  • Ok, that sounds excellent. Then I should look for a similar answer in the case of g++ which I use :) . – Zorglub29 Dec 01 '20 at 21:22
  • Ok so based on your comments, it seems that the answer is actually what is explained here: https://stackoverflow.com/questions/197675/how-does-delete-know-the-size-of-the-operand-array . I guess then that it means that there is no real way to get access t of this information, as this is much deeper in the implementation of how these new and delete work, right? – Zorglub29 Dec 01 '20 at 21:27
  • 1
    [https://stackoverflow.com/questions/852072/simple-c-implementation-to-track-memory-malloc-free](https://stackoverflow.com/questions/852072/simple-c-implementation-to-track-memory-malloc-free) This answer suggests a library that does the tracking for you: [https://stackoverflow.com/a/852532/487892](https://stackoverflow.com/a/852532/487892) – drescherjm Dec 01 '20 at 21:28
  • So this is basically what I should implement in a c++ context, right? – Zorglub29 Dec 01 '20 at 21:32
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/225378/discussion-between-drescherjm-and-zorglub29). – drescherjm Dec 01 '20 at 21:36

1 Answers1

2

It is implementation-defined as to which of those operator delete overloads will be called when deleting objects of incomplete type and arrays of non-class and trivially-destructible class types (ref1, ref2).

Vector is probably allocating chars or similar, so you're subject to this rule.

You can use the nbr_bytes argument to be more efficient if you get given it, but you'll have to store the information yourself if you want guaranteed access to it.

If you use a std::map to do so, be careful that you don't write yourself into a recursive disaster .

Asteroids With Wings
  • 17,071
  • 2
  • 21
  • 35
  • Ok, so you mean that which delete operator is called is implementation specific, right? But then, I do not understand how I get the [Free 1 byte] at addr 0x55b1c5d84280 message printed; this means that my re-defined delete operator has been called somehow. – Zorglub29 Dec 01 '20 at 21:19
  • @Zorglub29 Yes, but your first one, not your second one. You cannot rely on the second one ever being called. – Asteroids With Wings Dec 01 '20 at 21:27
  • Ok, thanks, with this and the comments on my question I think I understand. The problem is that there is, outside of my reach, some metadata about the block that is stored, right? :) . That would be a bit tricky to intercept then sounds like. – Zorglub29 Dec 01 '20 at 21:42
  • Well, yes and no. From the perspective of these operators, no, no such metadata exists anywhere aside from the argument to `operator new`, and that's entirely the point: it doesn't exist _because_ you didn't store it for later use. However, since you're delegating actual allocation to `malloc` and `free`, we can talk about the sort of data that _those_ things might store, and there the answer becomes "yes" on typical platforms for as long as you are indeed delegating to those allocation functions. – Asteroids With Wings Dec 01 '20 at 21:53