Getting size of dynamic C-style array vs. use of delete[]. Contradiction? [duplicate]












30
















This question already has an answer here:




  • C++ doesn't tell you the size of a dynamic array. But why?

    7 answers




I read everywhere that in C++ it is not possible to get the size of a dynamic array just from the pointer pointing to that chunk of memory.



How is it possible that there is no way of getting the size of a dynamic array just from the pointer, and at the same time it is possible to free all the memory allocated by using delete just on the pointer, without the need of specifying the array size?



delete must know the size of the array, right? Therefore this information must exist somewhere. Shouldn't it?



What is wrong in my reasoning?










share|improve this question















marked as duplicate by Ben Voigt c++
Users with the  c++ badge can single-handedly close c++ questions as duplicates and reopen them as needed.

StackExchange.ready(function() {
if (StackExchange.options.isMobile) return;

$('.dupe-hammer-message-hover:not(.hover-bound)').each(function() {
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');

$hover.hover(
function() {
$hover.showInfoMessage('', {
messageElement: $msg.clone().show(),
transient: false,
position: { my: 'bottom left', at: 'top center', offsetTop: -7 },
dismissable: false,
relativeToBody: true
});
},
function() {
StackExchange.helpers.removeMessages();
}
);
});
});
Feb 21 at 4:42


This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.














  • 7





    The underlying memory allocator knows the size of blocks it allocates, but there's no standard function that returns that information. There are sometimes non-standard malloc implementation specific ways but they're inherently non portable.

    – Shawn
    Feb 20 at 10:20








  • 5





    Why is this ever interesting? Use std::vector and never worry about delete.

    – n.m.
    Feb 20 at 10:21






  • 20





    @n.m. I don't get answers that tell you "don't bother". If one asks a question, there are reasons behind it. And the reasons don't have necessarily to be "practical reasons". It might be curiosity, it might be that I want to implement a compiler in machine code, or whatever. Even if we suppose one should always be backed by practical reasons in order to ask questions, I'm sure it is always possible to come up with at least one or two cases in which new knowledge could be used. There might be cases in which I cannot or don't want to use STL.

    – Michele Piccolini
    Feb 20 at 10:42






  • 3





    "If one asks a question, there are reasons behind it." These reasons are not necessarily valid. If you want to learn how to use C++ efficiently then not bothering with delete and pointers is the right thing. They are too low level and there are gazillion of these low level things of zero importance. Trying to learn them all is a waste of time. If you are in a situation where you cannot use std::vector (which should be extremely rare) you might want to look inside a typical implementation to learn how it works in order to replicate some of it.

    – n.m.
    Feb 20 at 11:10






  • 12





    @n.m. I don't think SO is limited to people "learning how to use C++ efficiently". Otherwise the language-lawyer tag would be pretty useless. Someone has to deal with all these "low level things", so why is asking about them on SO unreasonable?

    – Max Langhof
    Feb 20 at 11:50
















30
















This question already has an answer here:




  • C++ doesn't tell you the size of a dynamic array. But why?

    7 answers




I read everywhere that in C++ it is not possible to get the size of a dynamic array just from the pointer pointing to that chunk of memory.



How is it possible that there is no way of getting the size of a dynamic array just from the pointer, and at the same time it is possible to free all the memory allocated by using delete just on the pointer, without the need of specifying the array size?



delete must know the size of the array, right? Therefore this information must exist somewhere. Shouldn't it?



What is wrong in my reasoning?










share|improve this question















marked as duplicate by Ben Voigt c++
Users with the  c++ badge can single-handedly close c++ questions as duplicates and reopen them as needed.

StackExchange.ready(function() {
if (StackExchange.options.isMobile) return;

$('.dupe-hammer-message-hover:not(.hover-bound)').each(function() {
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');

$hover.hover(
function() {
$hover.showInfoMessage('', {
messageElement: $msg.clone().show(),
transient: false,
position: { my: 'bottom left', at: 'top center', offsetTop: -7 },
dismissable: false,
relativeToBody: true
});
},
function() {
StackExchange.helpers.removeMessages();
}
);
});
});
Feb 21 at 4:42


This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.














  • 7





    The underlying memory allocator knows the size of blocks it allocates, but there's no standard function that returns that information. There are sometimes non-standard malloc implementation specific ways but they're inherently non portable.

    – Shawn
    Feb 20 at 10:20








  • 5





    Why is this ever interesting? Use std::vector and never worry about delete.

    – n.m.
    Feb 20 at 10:21






  • 20





    @n.m. I don't get answers that tell you "don't bother". If one asks a question, there are reasons behind it. And the reasons don't have necessarily to be "practical reasons". It might be curiosity, it might be that I want to implement a compiler in machine code, or whatever. Even if we suppose one should always be backed by practical reasons in order to ask questions, I'm sure it is always possible to come up with at least one or two cases in which new knowledge could be used. There might be cases in which I cannot or don't want to use STL.

    – Michele Piccolini
    Feb 20 at 10:42






  • 3





    "If one asks a question, there are reasons behind it." These reasons are not necessarily valid. If you want to learn how to use C++ efficiently then not bothering with delete and pointers is the right thing. They are too low level and there are gazillion of these low level things of zero importance. Trying to learn them all is a waste of time. If you are in a situation where you cannot use std::vector (which should be extremely rare) you might want to look inside a typical implementation to learn how it works in order to replicate some of it.

    – n.m.
    Feb 20 at 11:10






  • 12





    @n.m. I don't think SO is limited to people "learning how to use C++ efficiently". Otherwise the language-lawyer tag would be pretty useless. Someone has to deal with all these "low level things", so why is asking about them on SO unreasonable?

    – Max Langhof
    Feb 20 at 11:50














30












30








30


1







This question already has an answer here:




  • C++ doesn't tell you the size of a dynamic array. But why?

    7 answers




I read everywhere that in C++ it is not possible to get the size of a dynamic array just from the pointer pointing to that chunk of memory.



How is it possible that there is no way of getting the size of a dynamic array just from the pointer, and at the same time it is possible to free all the memory allocated by using delete just on the pointer, without the need of specifying the array size?



delete must know the size of the array, right? Therefore this information must exist somewhere. Shouldn't it?



What is wrong in my reasoning?










share|improve this question

















This question already has an answer here:




  • C++ doesn't tell you the size of a dynamic array. But why?

    7 answers




I read everywhere that in C++ it is not possible to get the size of a dynamic array just from the pointer pointing to that chunk of memory.



How is it possible that there is no way of getting the size of a dynamic array just from the pointer, and at the same time it is possible to free all the memory allocated by using delete just on the pointer, without the need of specifying the array size?



delete must know the size of the array, right? Therefore this information must exist somewhere. Shouldn't it?



What is wrong in my reasoning?





This question already has an answer here:




  • C++ doesn't tell you the size of a dynamic array. But why?

    7 answers








c++ arrays heap






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Feb 20 at 14:51









Peter Mortensen

13.7k1986112




13.7k1986112










asked Feb 20 at 10:16









Michele PiccoliniMichele Piccolini

454210




454210




marked as duplicate by Ben Voigt c++
Users with the  c++ badge can single-handedly close c++ questions as duplicates and reopen them as needed.

StackExchange.ready(function() {
if (StackExchange.options.isMobile) return;

$('.dupe-hammer-message-hover:not(.hover-bound)').each(function() {
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');

$hover.hover(
function() {
$hover.showInfoMessage('', {
messageElement: $msg.clone().show(),
transient: false,
position: { my: 'bottom left', at: 'top center', offsetTop: -7 },
dismissable: false,
relativeToBody: true
});
},
function() {
StackExchange.helpers.removeMessages();
}
);
});
});
Feb 21 at 4:42


This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.









marked as duplicate by Ben Voigt c++
Users with the  c++ badge can single-handedly close c++ questions as duplicates and reopen them as needed.

StackExchange.ready(function() {
if (StackExchange.options.isMobile) return;

$('.dupe-hammer-message-hover:not(.hover-bound)').each(function() {
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');

$hover.hover(
function() {
$hover.showInfoMessage('', {
messageElement: $msg.clone().show(),
transient: false,
position: { my: 'bottom left', at: 'top center', offsetTop: -7 },
dismissable: false,
relativeToBody: true
});
},
function() {
StackExchange.helpers.removeMessages();
}
);
});
});
Feb 21 at 4:42


This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.










  • 7





    The underlying memory allocator knows the size of blocks it allocates, but there's no standard function that returns that information. There are sometimes non-standard malloc implementation specific ways but they're inherently non portable.

    – Shawn
    Feb 20 at 10:20








  • 5





    Why is this ever interesting? Use std::vector and never worry about delete.

    – n.m.
    Feb 20 at 10:21






  • 20





    @n.m. I don't get answers that tell you "don't bother". If one asks a question, there are reasons behind it. And the reasons don't have necessarily to be "practical reasons". It might be curiosity, it might be that I want to implement a compiler in machine code, or whatever. Even if we suppose one should always be backed by practical reasons in order to ask questions, I'm sure it is always possible to come up with at least one or two cases in which new knowledge could be used. There might be cases in which I cannot or don't want to use STL.

    – Michele Piccolini
    Feb 20 at 10:42






  • 3





    "If one asks a question, there are reasons behind it." These reasons are not necessarily valid. If you want to learn how to use C++ efficiently then not bothering with delete and pointers is the right thing. They are too low level and there are gazillion of these low level things of zero importance. Trying to learn them all is a waste of time. If you are in a situation where you cannot use std::vector (which should be extremely rare) you might want to look inside a typical implementation to learn how it works in order to replicate some of it.

    – n.m.
    Feb 20 at 11:10






  • 12





    @n.m. I don't think SO is limited to people "learning how to use C++ efficiently". Otherwise the language-lawyer tag would be pretty useless. Someone has to deal with all these "low level things", so why is asking about them on SO unreasonable?

    – Max Langhof
    Feb 20 at 11:50














  • 7





    The underlying memory allocator knows the size of blocks it allocates, but there's no standard function that returns that information. There are sometimes non-standard malloc implementation specific ways but they're inherently non portable.

    – Shawn
    Feb 20 at 10:20








  • 5





    Why is this ever interesting? Use std::vector and never worry about delete.

    – n.m.
    Feb 20 at 10:21






  • 20





    @n.m. I don't get answers that tell you "don't bother". If one asks a question, there are reasons behind it. And the reasons don't have necessarily to be "practical reasons". It might be curiosity, it might be that I want to implement a compiler in machine code, or whatever. Even if we suppose one should always be backed by practical reasons in order to ask questions, I'm sure it is always possible to come up with at least one or two cases in which new knowledge could be used. There might be cases in which I cannot or don't want to use STL.

    – Michele Piccolini
    Feb 20 at 10:42






  • 3





    "If one asks a question, there are reasons behind it." These reasons are not necessarily valid. If you want to learn how to use C++ efficiently then not bothering with delete and pointers is the right thing. They are too low level and there are gazillion of these low level things of zero importance. Trying to learn them all is a waste of time. If you are in a situation where you cannot use std::vector (which should be extremely rare) you might want to look inside a typical implementation to learn how it works in order to replicate some of it.

    – n.m.
    Feb 20 at 11:10






  • 12





    @n.m. I don't think SO is limited to people "learning how to use C++ efficiently". Otherwise the language-lawyer tag would be pretty useless. Someone has to deal with all these "low level things", so why is asking about them on SO unreasonable?

    – Max Langhof
    Feb 20 at 11:50








7




7





The underlying memory allocator knows the size of blocks it allocates, but there's no standard function that returns that information. There are sometimes non-standard malloc implementation specific ways but they're inherently non portable.

– Shawn
Feb 20 at 10:20







The underlying memory allocator knows the size of blocks it allocates, but there's no standard function that returns that information. There are sometimes non-standard malloc implementation specific ways but they're inherently non portable.

– Shawn
Feb 20 at 10:20






5




5





Why is this ever interesting? Use std::vector and never worry about delete.

– n.m.
Feb 20 at 10:21





Why is this ever interesting? Use std::vector and never worry about delete.

– n.m.
Feb 20 at 10:21




20




20





@n.m. I don't get answers that tell you "don't bother". If one asks a question, there are reasons behind it. And the reasons don't have necessarily to be "practical reasons". It might be curiosity, it might be that I want to implement a compiler in machine code, or whatever. Even if we suppose one should always be backed by practical reasons in order to ask questions, I'm sure it is always possible to come up with at least one or two cases in which new knowledge could be used. There might be cases in which I cannot or don't want to use STL.

– Michele Piccolini
Feb 20 at 10:42





@n.m. I don't get answers that tell you "don't bother". If one asks a question, there are reasons behind it. And the reasons don't have necessarily to be "practical reasons". It might be curiosity, it might be that I want to implement a compiler in machine code, or whatever. Even if we suppose one should always be backed by practical reasons in order to ask questions, I'm sure it is always possible to come up with at least one or two cases in which new knowledge could be used. There might be cases in which I cannot or don't want to use STL.

– Michele Piccolini
Feb 20 at 10:42




3




3





"If one asks a question, there are reasons behind it." These reasons are not necessarily valid. If you want to learn how to use C++ efficiently then not bothering with delete and pointers is the right thing. They are too low level and there are gazillion of these low level things of zero importance. Trying to learn them all is a waste of time. If you are in a situation where you cannot use std::vector (which should be extremely rare) you might want to look inside a typical implementation to learn how it works in order to replicate some of it.

– n.m.
Feb 20 at 11:10





"If one asks a question, there are reasons behind it." These reasons are not necessarily valid. If you want to learn how to use C++ efficiently then not bothering with delete and pointers is the right thing. They are too low level and there are gazillion of these low level things of zero importance. Trying to learn them all is a waste of time. If you are in a situation where you cannot use std::vector (which should be extremely rare) you might want to look inside a typical implementation to learn how it works in order to replicate some of it.

– n.m.
Feb 20 at 11:10




12




12





@n.m. I don't think SO is limited to people "learning how to use C++ efficiently". Otherwise the language-lawyer tag would be pretty useless. Someone has to deal with all these "low level things", so why is asking about them on SO unreasonable?

– Max Langhof
Feb 20 at 11:50





@n.m. I don't think SO is limited to people "learning how to use C++ efficiently". Otherwise the language-lawyer tag would be pretty useless. Someone has to deal with all these "low level things", so why is asking about them on SO unreasonable?

– Max Langhof
Feb 20 at 11:50












5 Answers
5






active

oldest

votes


















28














TL;DR The operator delete destructs the objects and deallocates the memory. The information N ("number of elements") is required for destructing. The information S ("size of allocated memory") is required for deallocating. S is always stored and can be queried by compiler extensions. N is only stored if destructing objects requires calling destructors. If N is stored, where it is stored is implementation-dependent.





The operator delete has to do two things:



a) destructing the objects (calling destructors, if necessary) and



b) deallocating the memory.



Let's first discuss (de)allocation, which
is delegated to the C functions malloc and free by many compilers (like GCC). The function malloc takes the number of bytes to be allocated as a parameter and returns a pointer. The function free takes only a pointer; the number of bytes is not necessary. This means that the memory allocating functions have to keep track how many bytes have been allocated. There could be a function to query how many bytes have been allocated (in Linux this can be done with malloc_usable_size, in Windows with _msize). This is not what you want because this does not tell you the size of an array but the amount of memory allocated. Since malloc is not necessarily giving you exactly as much memory as you have asked for, you cannot compute the array size from the result of malloc_usable_size:



#include <iostream>
#include <malloc.h>

int main()
{
std::cout << malloc_usable_size(malloc(42)) << std::endl;
}


This example gives you 56, not 42: http://cpp.sh/2wdm4



Note that applying malloc_usable_size (or _msize) to the result of new is undefined behavior.



So, let's now discuss construction and destruction of objects. Here, you have two ways of delete: delete (for single objects) and delete (for arrays). In very old versions of C++, you had to pass the size of the array to the delete-operator. As you mentioned, nowadays, this is not the case. The compiler tracks this information. GCC adds a small field prior the beginning of the array, where the size of the array is stored such that it knows how often the destructor has to be called. You might query that:



#include <iostream>

struct foo {
char a;
~foo() {}
};

int main()
{
foo * ptr = new foo[42];
std::cout << *(((std::size_t*)ptr)-1) << std::endl;
}


This code gives you 42: http://cpp.sh/7mbqq



Just for the protocol: This is undefined behavior, but with the current version of GCC it works.



So, you might ask yourself why there is no function to query this information. The answer is that GCC doesn't always store this information. There might be cases where destruction of the objects is a no-operation (and the compiler is able to figure that out). Consider the following example:



#include <iostream>

struct foo {
char a;
//~foo() {}
};

int main()
{
foo * ptr = new foo[42];
std::cout << *(((std::size_t*)ptr)-1) << std::endl;
}


Here, the answer is not 42 any more: http://cpp.sh/2rzfb



The answer is just garbage - the code was undefined behavior again.



Why? Because the compiler does not need to call a destructor, so it does not need to store the information. And, yes, in this case the compiler does not add code that keeps track how many objects have been created. Only the number of allocated bytes (which might be 56, see above) is known.






share|improve this answer





















  • 1





    Very interesting answer! I do wonder now what malloc_usable_size would give you for that second pointer though? And if it's the correct answer, where this information would have been stored?

    – Max Langhof
    Feb 20 at 13:22






  • 1





    You can try this out but this is undefined behavior. For gcc, where new is based on malloc, it could work. However, if you consider an array of a not-trivally-destructible type (first example), ptr does for sure not point to the beginning of the memory that has been allocated by malloc (because of the hidden field in the beginning). Thus, I expect that malloc_usable_size does not work.

    – Handy999
    Feb 20 at 13:28








  • 3





    Wonderful answer! So, the gist is: * The information N ("number of elements") may not be stored (it is only in case of dynamic arrays of things with a destructor). For this reason we need to keep track of the length manually, if we want it. * What is instead always stored is S ("size of allocated memory"). (S can be queried but results are implementation-dependent). * delete only needs S in order to deallocate memory (treats everything like a blob). It needs N only to know how many times to call destructors. * If N is stored, where it is stored is implementation-dependent. Correct?

    – Michele Piccolini
    Feb 20 at 17:22











  • @Michele Piccolini: yes, excatly.

    – Handy999
    Feb 20 at 18:15






  • 1





    @Michele Piccolini: do you like it like this?

    – Handy999
    Feb 21 at 7:10



















25














It does - the allocator, or some implementation detail behind it, knows exactly what the size of the block is.



But that information is not provided to you or to the "code layer" of your program.



Could the language have been designed to do this? Sure! It's probably a case of "don't pay for what you don't use" — it's your responsibility to remember this information. After all, you know how much memory you asked for! Often times people will not want the cost of a number being passed up the call stack when, most of the time, they won't need it to be.



There are some platform-specific "extensions" that may get you what you want, like malloc_usable_size on Linux and _msize on Windows, though these assume that your allocator used malloc and didn't do any other magic that may extend the size of the allocated block at the lowest level. I'd say you're still better off tracking this yourself if you really need it… or using a vector.






share|improve this answer





















  • 4





    @MaxLanghof "If I have to keep track of it, then I have to pay extra at some point" The key word is if.

    – Lightness Races in Orbit
    Feb 20 at 10:26






  • 4





    @MaxLanghof Admittedly I would be vaguely interested in finding out whether there's some crucial reason that this wasn't made part of the stdlib's allocation interface(s), that go beyond "we cba and don't think you should need this"

    – Lightness Races in Orbit
    Feb 20 at 10:32






  • 1





    @MichelePiccolini The first question in your comment is unrelated to the topic at hand - correctly deleteing a pointer to an array if you already know it is a pointer to an array and being able to infer whether a pointer points to an array or a single object are two different, unrelated things. In other words, if there was an operator to infer the size that delete uses it would most certainly have UB if used on non-array allocations, thus it wouldn't allow you to decide whether the pointer is to an array allocation or not.

    – Max Langhof
    Feb 20 at 11:45








  • 2





    @MichelePiccolini You shouldn't really be using delete or delete at all, though; that's for the insides of containers and smart pointers, which do have all this information nicely tucked away.

    – Lightness Races in Orbit
    Feb 20 at 11:57






  • 2





    It might not know exactly, it might only know the size of the block it chose, which might tell it the size rounded up to the next multiple of 16 bytes, for example. Depending on the allocator of course. xD, @Handy999 already posted this as an answer before I commented.

    – Peter Cordes
    Feb 20 at 17:38





















5














I think the reason for this is a confluence of three factors.




  1. C++ has a "you only pay for what you use" culture

  2. C++ started its life as a pre-processor for C and hence had to be built on top of what C offered.

  3. C++ is one of the most widely ported languages around. Features that make life difficult for existing ports are unlikely to get added.


C allows the programmer to free memory blocks without specifying the size of the memory block to free, but does not provide the programmer with any standard way to access the size of the allocation. Furthermore the actual amount of memory allocated may well be larger than the amount the programmer asked for.



Following the principle of "you only pay for what you use", C++ implementations implement new differently for different types. Typically they only store the size if it is necessary to do so, usually because the type has a non-trivial destructor.



So while yes, enough information is stored to free the memory block, it would be very difficult to define a sane and portable API for accessing that information. Depending on the data type and platform, the actual requested size may be available (for types where the C++ implementation has to store it), only the actual allocated size may be available (for types where the C++ implementation does not have to store it on platforms where the underlying memory manager has an extension to get the allocated size), or the size may not be available at all (for types where the C++ implementation does not have to store it on platforms that don't provide access to the information from the underlying memory manager).






share|improve this answer

































    1














    This answer applies to Microsoft Visual Studio only.



    There is a function called _msize, which will return the malloced / calloced / realloced size of a pointer.



    It can be found in the malloc.h header, and the parameters are:



    size_t _msize(
    void *memblock
    );


    I am not sure if there is an equivalent in gcc. There probably should be.






    share|improve this answer



















    • 1





      Ahh there is malloc_usable_size() for linux.

      – Owl
      Feb 20 at 10:42











    • Do you know if those are reliable or what could be some cases that might arise and might make the usage of these non reliable?

      – Michele Piccolini
      Feb 20 at 11:01






    • 2





      Well one of the things I noticed when I tested it, I called a malloc on an array of chars 25 long, then called malloc_usable_size on the array. It reported 40 bytes used. This suggests to me that it's actually reporting the container size allocated that is large enough to contain the array.

      – Owl
      Feb 20 at 14:37



















    -1














    If delete doesn't have to know the size of the array at the time it is called, your entire argument falls apart. And delete doesn't have to know the size of the array at the time it is called. It only needs to know the size to make the block available for use by others, and absolutely nothing requires it to make the block available for use by others at the time delete is called.



    For example, delete my dice a large block into some number of smaller blocks. Each of those blocks but one need only have a pointer to the control block that knows the size. If any block but the control block is passed to delete first, then delete has no idea how big the block that was just freed is and won't know until later.



    That it is not absolutely required that delete know the size of a block at every arbitrary point during its lifetime is sufficient to invalidate your argument.






    share|improve this answer






























      5 Answers
      5






      active

      oldest

      votes








      5 Answers
      5






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      28














      TL;DR The operator delete destructs the objects and deallocates the memory. The information N ("number of elements") is required for destructing. The information S ("size of allocated memory") is required for deallocating. S is always stored and can be queried by compiler extensions. N is only stored if destructing objects requires calling destructors. If N is stored, where it is stored is implementation-dependent.





      The operator delete has to do two things:



      a) destructing the objects (calling destructors, if necessary) and



      b) deallocating the memory.



      Let's first discuss (de)allocation, which
      is delegated to the C functions malloc and free by many compilers (like GCC). The function malloc takes the number of bytes to be allocated as a parameter and returns a pointer. The function free takes only a pointer; the number of bytes is not necessary. This means that the memory allocating functions have to keep track how many bytes have been allocated. There could be a function to query how many bytes have been allocated (in Linux this can be done with malloc_usable_size, in Windows with _msize). This is not what you want because this does not tell you the size of an array but the amount of memory allocated. Since malloc is not necessarily giving you exactly as much memory as you have asked for, you cannot compute the array size from the result of malloc_usable_size:



      #include <iostream>
      #include <malloc.h>

      int main()
      {
      std::cout << malloc_usable_size(malloc(42)) << std::endl;
      }


      This example gives you 56, not 42: http://cpp.sh/2wdm4



      Note that applying malloc_usable_size (or _msize) to the result of new is undefined behavior.



      So, let's now discuss construction and destruction of objects. Here, you have two ways of delete: delete (for single objects) and delete (for arrays). In very old versions of C++, you had to pass the size of the array to the delete-operator. As you mentioned, nowadays, this is not the case. The compiler tracks this information. GCC adds a small field prior the beginning of the array, where the size of the array is stored such that it knows how often the destructor has to be called. You might query that:



      #include <iostream>

      struct foo {
      char a;
      ~foo() {}
      };

      int main()
      {
      foo * ptr = new foo[42];
      std::cout << *(((std::size_t*)ptr)-1) << std::endl;
      }


      This code gives you 42: http://cpp.sh/7mbqq



      Just for the protocol: This is undefined behavior, but with the current version of GCC it works.



      So, you might ask yourself why there is no function to query this information. The answer is that GCC doesn't always store this information. There might be cases where destruction of the objects is a no-operation (and the compiler is able to figure that out). Consider the following example:



      #include <iostream>

      struct foo {
      char a;
      //~foo() {}
      };

      int main()
      {
      foo * ptr = new foo[42];
      std::cout << *(((std::size_t*)ptr)-1) << std::endl;
      }


      Here, the answer is not 42 any more: http://cpp.sh/2rzfb



      The answer is just garbage - the code was undefined behavior again.



      Why? Because the compiler does not need to call a destructor, so it does not need to store the information. And, yes, in this case the compiler does not add code that keeps track how many objects have been created. Only the number of allocated bytes (which might be 56, see above) is known.






      share|improve this answer





















      • 1





        Very interesting answer! I do wonder now what malloc_usable_size would give you for that second pointer though? And if it's the correct answer, where this information would have been stored?

        – Max Langhof
        Feb 20 at 13:22






      • 1





        You can try this out but this is undefined behavior. For gcc, where new is based on malloc, it could work. However, if you consider an array of a not-trivally-destructible type (first example), ptr does for sure not point to the beginning of the memory that has been allocated by malloc (because of the hidden field in the beginning). Thus, I expect that malloc_usable_size does not work.

        – Handy999
        Feb 20 at 13:28








      • 3





        Wonderful answer! So, the gist is: * The information N ("number of elements") may not be stored (it is only in case of dynamic arrays of things with a destructor). For this reason we need to keep track of the length manually, if we want it. * What is instead always stored is S ("size of allocated memory"). (S can be queried but results are implementation-dependent). * delete only needs S in order to deallocate memory (treats everything like a blob). It needs N only to know how many times to call destructors. * If N is stored, where it is stored is implementation-dependent. Correct?

        – Michele Piccolini
        Feb 20 at 17:22











      • @Michele Piccolini: yes, excatly.

        – Handy999
        Feb 20 at 18:15






      • 1





        @Michele Piccolini: do you like it like this?

        – Handy999
        Feb 21 at 7:10
















      28














      TL;DR The operator delete destructs the objects and deallocates the memory. The information N ("number of elements") is required for destructing. The information S ("size of allocated memory") is required for deallocating. S is always stored and can be queried by compiler extensions. N is only stored if destructing objects requires calling destructors. If N is stored, where it is stored is implementation-dependent.





      The operator delete has to do two things:



      a) destructing the objects (calling destructors, if necessary) and



      b) deallocating the memory.



      Let's first discuss (de)allocation, which
      is delegated to the C functions malloc and free by many compilers (like GCC). The function malloc takes the number of bytes to be allocated as a parameter and returns a pointer. The function free takes only a pointer; the number of bytes is not necessary. This means that the memory allocating functions have to keep track how many bytes have been allocated. There could be a function to query how many bytes have been allocated (in Linux this can be done with malloc_usable_size, in Windows with _msize). This is not what you want because this does not tell you the size of an array but the amount of memory allocated. Since malloc is not necessarily giving you exactly as much memory as you have asked for, you cannot compute the array size from the result of malloc_usable_size:



      #include <iostream>
      #include <malloc.h>

      int main()
      {
      std::cout << malloc_usable_size(malloc(42)) << std::endl;
      }


      This example gives you 56, not 42: http://cpp.sh/2wdm4



      Note that applying malloc_usable_size (or _msize) to the result of new is undefined behavior.



      So, let's now discuss construction and destruction of objects. Here, you have two ways of delete: delete (for single objects) and delete (for arrays). In very old versions of C++, you had to pass the size of the array to the delete-operator. As you mentioned, nowadays, this is not the case. The compiler tracks this information. GCC adds a small field prior the beginning of the array, where the size of the array is stored such that it knows how often the destructor has to be called. You might query that:



      #include <iostream>

      struct foo {
      char a;
      ~foo() {}
      };

      int main()
      {
      foo * ptr = new foo[42];
      std::cout << *(((std::size_t*)ptr)-1) << std::endl;
      }


      This code gives you 42: http://cpp.sh/7mbqq



      Just for the protocol: This is undefined behavior, but with the current version of GCC it works.



      So, you might ask yourself why there is no function to query this information. The answer is that GCC doesn't always store this information. There might be cases where destruction of the objects is a no-operation (and the compiler is able to figure that out). Consider the following example:



      #include <iostream>

      struct foo {
      char a;
      //~foo() {}
      };

      int main()
      {
      foo * ptr = new foo[42];
      std::cout << *(((std::size_t*)ptr)-1) << std::endl;
      }


      Here, the answer is not 42 any more: http://cpp.sh/2rzfb



      The answer is just garbage - the code was undefined behavior again.



      Why? Because the compiler does not need to call a destructor, so it does not need to store the information. And, yes, in this case the compiler does not add code that keeps track how many objects have been created. Only the number of allocated bytes (which might be 56, see above) is known.






      share|improve this answer





















      • 1





        Very interesting answer! I do wonder now what malloc_usable_size would give you for that second pointer though? And if it's the correct answer, where this information would have been stored?

        – Max Langhof
        Feb 20 at 13:22






      • 1





        You can try this out but this is undefined behavior. For gcc, where new is based on malloc, it could work. However, if you consider an array of a not-trivally-destructible type (first example), ptr does for sure not point to the beginning of the memory that has been allocated by malloc (because of the hidden field in the beginning). Thus, I expect that malloc_usable_size does not work.

        – Handy999
        Feb 20 at 13:28








      • 3





        Wonderful answer! So, the gist is: * The information N ("number of elements") may not be stored (it is only in case of dynamic arrays of things with a destructor). For this reason we need to keep track of the length manually, if we want it. * What is instead always stored is S ("size of allocated memory"). (S can be queried but results are implementation-dependent). * delete only needs S in order to deallocate memory (treats everything like a blob). It needs N only to know how many times to call destructors. * If N is stored, where it is stored is implementation-dependent. Correct?

        – Michele Piccolini
        Feb 20 at 17:22











      • @Michele Piccolini: yes, excatly.

        – Handy999
        Feb 20 at 18:15






      • 1





        @Michele Piccolini: do you like it like this?

        – Handy999
        Feb 21 at 7:10














      28












      28








      28







      TL;DR The operator delete destructs the objects and deallocates the memory. The information N ("number of elements") is required for destructing. The information S ("size of allocated memory") is required for deallocating. S is always stored and can be queried by compiler extensions. N is only stored if destructing objects requires calling destructors. If N is stored, where it is stored is implementation-dependent.





      The operator delete has to do two things:



      a) destructing the objects (calling destructors, if necessary) and



      b) deallocating the memory.



      Let's first discuss (de)allocation, which
      is delegated to the C functions malloc and free by many compilers (like GCC). The function malloc takes the number of bytes to be allocated as a parameter and returns a pointer. The function free takes only a pointer; the number of bytes is not necessary. This means that the memory allocating functions have to keep track how many bytes have been allocated. There could be a function to query how many bytes have been allocated (in Linux this can be done with malloc_usable_size, in Windows with _msize). This is not what you want because this does not tell you the size of an array but the amount of memory allocated. Since malloc is not necessarily giving you exactly as much memory as you have asked for, you cannot compute the array size from the result of malloc_usable_size:



      #include <iostream>
      #include <malloc.h>

      int main()
      {
      std::cout << malloc_usable_size(malloc(42)) << std::endl;
      }


      This example gives you 56, not 42: http://cpp.sh/2wdm4



      Note that applying malloc_usable_size (or _msize) to the result of new is undefined behavior.



      So, let's now discuss construction and destruction of objects. Here, you have two ways of delete: delete (for single objects) and delete (for arrays). In very old versions of C++, you had to pass the size of the array to the delete-operator. As you mentioned, nowadays, this is not the case. The compiler tracks this information. GCC adds a small field prior the beginning of the array, where the size of the array is stored such that it knows how often the destructor has to be called. You might query that:



      #include <iostream>

      struct foo {
      char a;
      ~foo() {}
      };

      int main()
      {
      foo * ptr = new foo[42];
      std::cout << *(((std::size_t*)ptr)-1) << std::endl;
      }


      This code gives you 42: http://cpp.sh/7mbqq



      Just for the protocol: This is undefined behavior, but with the current version of GCC it works.



      So, you might ask yourself why there is no function to query this information. The answer is that GCC doesn't always store this information. There might be cases where destruction of the objects is a no-operation (and the compiler is able to figure that out). Consider the following example:



      #include <iostream>

      struct foo {
      char a;
      //~foo() {}
      };

      int main()
      {
      foo * ptr = new foo[42];
      std::cout << *(((std::size_t*)ptr)-1) << std::endl;
      }


      Here, the answer is not 42 any more: http://cpp.sh/2rzfb



      The answer is just garbage - the code was undefined behavior again.



      Why? Because the compiler does not need to call a destructor, so it does not need to store the information. And, yes, in this case the compiler does not add code that keeps track how many objects have been created. Only the number of allocated bytes (which might be 56, see above) is known.






      share|improve this answer















      TL;DR The operator delete destructs the objects and deallocates the memory. The information N ("number of elements") is required for destructing. The information S ("size of allocated memory") is required for deallocating. S is always stored and can be queried by compiler extensions. N is only stored if destructing objects requires calling destructors. If N is stored, where it is stored is implementation-dependent.





      The operator delete has to do two things:



      a) destructing the objects (calling destructors, if necessary) and



      b) deallocating the memory.



      Let's first discuss (de)allocation, which
      is delegated to the C functions malloc and free by many compilers (like GCC). The function malloc takes the number of bytes to be allocated as a parameter and returns a pointer. The function free takes only a pointer; the number of bytes is not necessary. This means that the memory allocating functions have to keep track how many bytes have been allocated. There could be a function to query how many bytes have been allocated (in Linux this can be done with malloc_usable_size, in Windows with _msize). This is not what you want because this does not tell you the size of an array but the amount of memory allocated. Since malloc is not necessarily giving you exactly as much memory as you have asked for, you cannot compute the array size from the result of malloc_usable_size:



      #include <iostream>
      #include <malloc.h>

      int main()
      {
      std::cout << malloc_usable_size(malloc(42)) << std::endl;
      }


      This example gives you 56, not 42: http://cpp.sh/2wdm4



      Note that applying malloc_usable_size (or _msize) to the result of new is undefined behavior.



      So, let's now discuss construction and destruction of objects. Here, you have two ways of delete: delete (for single objects) and delete (for arrays). In very old versions of C++, you had to pass the size of the array to the delete-operator. As you mentioned, nowadays, this is not the case. The compiler tracks this information. GCC adds a small field prior the beginning of the array, where the size of the array is stored such that it knows how often the destructor has to be called. You might query that:



      #include <iostream>

      struct foo {
      char a;
      ~foo() {}
      };

      int main()
      {
      foo * ptr = new foo[42];
      std::cout << *(((std::size_t*)ptr)-1) << std::endl;
      }


      This code gives you 42: http://cpp.sh/7mbqq



      Just for the protocol: This is undefined behavior, but with the current version of GCC it works.



      So, you might ask yourself why there is no function to query this information. The answer is that GCC doesn't always store this information. There might be cases where destruction of the objects is a no-operation (and the compiler is able to figure that out). Consider the following example:



      #include <iostream>

      struct foo {
      char a;
      //~foo() {}
      };

      int main()
      {
      foo * ptr = new foo[42];
      std::cout << *(((std::size_t*)ptr)-1) << std::endl;
      }


      Here, the answer is not 42 any more: http://cpp.sh/2rzfb



      The answer is just garbage - the code was undefined behavior again.



      Why? Because the compiler does not need to call a destructor, so it does not need to store the information. And, yes, in this case the compiler does not add code that keeps track how many objects have been created. Only the number of allocated bytes (which might be 56, see above) is known.







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Feb 21 at 7:08

























      answered Feb 20 at 12:42









      Handy999Handy999

      55417




      55417








      • 1





        Very interesting answer! I do wonder now what malloc_usable_size would give you for that second pointer though? And if it's the correct answer, where this information would have been stored?

        – Max Langhof
        Feb 20 at 13:22






      • 1





        You can try this out but this is undefined behavior. For gcc, where new is based on malloc, it could work. However, if you consider an array of a not-trivally-destructible type (first example), ptr does for sure not point to the beginning of the memory that has been allocated by malloc (because of the hidden field in the beginning). Thus, I expect that malloc_usable_size does not work.

        – Handy999
        Feb 20 at 13:28








      • 3





        Wonderful answer! So, the gist is: * The information N ("number of elements") may not be stored (it is only in case of dynamic arrays of things with a destructor). For this reason we need to keep track of the length manually, if we want it. * What is instead always stored is S ("size of allocated memory"). (S can be queried but results are implementation-dependent). * delete only needs S in order to deallocate memory (treats everything like a blob). It needs N only to know how many times to call destructors. * If N is stored, where it is stored is implementation-dependent. Correct?

        – Michele Piccolini
        Feb 20 at 17:22











      • @Michele Piccolini: yes, excatly.

        – Handy999
        Feb 20 at 18:15






      • 1





        @Michele Piccolini: do you like it like this?

        – Handy999
        Feb 21 at 7:10














      • 1





        Very interesting answer! I do wonder now what malloc_usable_size would give you for that second pointer though? And if it's the correct answer, where this information would have been stored?

        – Max Langhof
        Feb 20 at 13:22






      • 1





        You can try this out but this is undefined behavior. For gcc, where new is based on malloc, it could work. However, if you consider an array of a not-trivally-destructible type (first example), ptr does for sure not point to the beginning of the memory that has been allocated by malloc (because of the hidden field in the beginning). Thus, I expect that malloc_usable_size does not work.

        – Handy999
        Feb 20 at 13:28








      • 3





        Wonderful answer! So, the gist is: * The information N ("number of elements") may not be stored (it is only in case of dynamic arrays of things with a destructor). For this reason we need to keep track of the length manually, if we want it. * What is instead always stored is S ("size of allocated memory"). (S can be queried but results are implementation-dependent). * delete only needs S in order to deallocate memory (treats everything like a blob). It needs N only to know how many times to call destructors. * If N is stored, where it is stored is implementation-dependent. Correct?

        – Michele Piccolini
        Feb 20 at 17:22











      • @Michele Piccolini: yes, excatly.

        – Handy999
        Feb 20 at 18:15






      • 1





        @Michele Piccolini: do you like it like this?

        – Handy999
        Feb 21 at 7:10








      1




      1





      Very interesting answer! I do wonder now what malloc_usable_size would give you for that second pointer though? And if it's the correct answer, where this information would have been stored?

      – Max Langhof
      Feb 20 at 13:22





      Very interesting answer! I do wonder now what malloc_usable_size would give you for that second pointer though? And if it's the correct answer, where this information would have been stored?

      – Max Langhof
      Feb 20 at 13:22




      1




      1





      You can try this out but this is undefined behavior. For gcc, where new is based on malloc, it could work. However, if you consider an array of a not-trivally-destructible type (first example), ptr does for sure not point to the beginning of the memory that has been allocated by malloc (because of the hidden field in the beginning). Thus, I expect that malloc_usable_size does not work.

      – Handy999
      Feb 20 at 13:28







      You can try this out but this is undefined behavior. For gcc, where new is based on malloc, it could work. However, if you consider an array of a not-trivally-destructible type (first example), ptr does for sure not point to the beginning of the memory that has been allocated by malloc (because of the hidden field in the beginning). Thus, I expect that malloc_usable_size does not work.

      – Handy999
      Feb 20 at 13:28






      3




      3





      Wonderful answer! So, the gist is: * The information N ("number of elements") may not be stored (it is only in case of dynamic arrays of things with a destructor). For this reason we need to keep track of the length manually, if we want it. * What is instead always stored is S ("size of allocated memory"). (S can be queried but results are implementation-dependent). * delete only needs S in order to deallocate memory (treats everything like a blob). It needs N only to know how many times to call destructors. * If N is stored, where it is stored is implementation-dependent. Correct?

      – Michele Piccolini
      Feb 20 at 17:22





      Wonderful answer! So, the gist is: * The information N ("number of elements") may not be stored (it is only in case of dynamic arrays of things with a destructor). For this reason we need to keep track of the length manually, if we want it. * What is instead always stored is S ("size of allocated memory"). (S can be queried but results are implementation-dependent). * delete only needs S in order to deallocate memory (treats everything like a blob). It needs N only to know how many times to call destructors. * If N is stored, where it is stored is implementation-dependent. Correct?

      – Michele Piccolini
      Feb 20 at 17:22













      @Michele Piccolini: yes, excatly.

      – Handy999
      Feb 20 at 18:15





      @Michele Piccolini: yes, excatly.

      – Handy999
      Feb 20 at 18:15




      1




      1





      @Michele Piccolini: do you like it like this?

      – Handy999
      Feb 21 at 7:10





      @Michele Piccolini: do you like it like this?

      – Handy999
      Feb 21 at 7:10













      25














      It does - the allocator, or some implementation detail behind it, knows exactly what the size of the block is.



      But that information is not provided to you or to the "code layer" of your program.



      Could the language have been designed to do this? Sure! It's probably a case of "don't pay for what you don't use" — it's your responsibility to remember this information. After all, you know how much memory you asked for! Often times people will not want the cost of a number being passed up the call stack when, most of the time, they won't need it to be.



      There are some platform-specific "extensions" that may get you what you want, like malloc_usable_size on Linux and _msize on Windows, though these assume that your allocator used malloc and didn't do any other magic that may extend the size of the allocated block at the lowest level. I'd say you're still better off tracking this yourself if you really need it… or using a vector.






      share|improve this answer





















      • 4





        @MaxLanghof "If I have to keep track of it, then I have to pay extra at some point" The key word is if.

        – Lightness Races in Orbit
        Feb 20 at 10:26






      • 4





        @MaxLanghof Admittedly I would be vaguely interested in finding out whether there's some crucial reason that this wasn't made part of the stdlib's allocation interface(s), that go beyond "we cba and don't think you should need this"

        – Lightness Races in Orbit
        Feb 20 at 10:32






      • 1





        @MichelePiccolini The first question in your comment is unrelated to the topic at hand - correctly deleteing a pointer to an array if you already know it is a pointer to an array and being able to infer whether a pointer points to an array or a single object are two different, unrelated things. In other words, if there was an operator to infer the size that delete uses it would most certainly have UB if used on non-array allocations, thus it wouldn't allow you to decide whether the pointer is to an array allocation or not.

        – Max Langhof
        Feb 20 at 11:45








      • 2





        @MichelePiccolini You shouldn't really be using delete or delete at all, though; that's for the insides of containers and smart pointers, which do have all this information nicely tucked away.

        – Lightness Races in Orbit
        Feb 20 at 11:57






      • 2





        It might not know exactly, it might only know the size of the block it chose, which might tell it the size rounded up to the next multiple of 16 bytes, for example. Depending on the allocator of course. xD, @Handy999 already posted this as an answer before I commented.

        – Peter Cordes
        Feb 20 at 17:38


















      25














      It does - the allocator, or some implementation detail behind it, knows exactly what the size of the block is.



      But that information is not provided to you or to the "code layer" of your program.



      Could the language have been designed to do this? Sure! It's probably a case of "don't pay for what you don't use" — it's your responsibility to remember this information. After all, you know how much memory you asked for! Often times people will not want the cost of a number being passed up the call stack when, most of the time, they won't need it to be.



      There are some platform-specific "extensions" that may get you what you want, like malloc_usable_size on Linux and _msize on Windows, though these assume that your allocator used malloc and didn't do any other magic that may extend the size of the allocated block at the lowest level. I'd say you're still better off tracking this yourself if you really need it… or using a vector.






      share|improve this answer





















      • 4





        @MaxLanghof "If I have to keep track of it, then I have to pay extra at some point" The key word is if.

        – Lightness Races in Orbit
        Feb 20 at 10:26






      • 4





        @MaxLanghof Admittedly I would be vaguely interested in finding out whether there's some crucial reason that this wasn't made part of the stdlib's allocation interface(s), that go beyond "we cba and don't think you should need this"

        – Lightness Races in Orbit
        Feb 20 at 10:32






      • 1





        @MichelePiccolini The first question in your comment is unrelated to the topic at hand - correctly deleteing a pointer to an array if you already know it is a pointer to an array and being able to infer whether a pointer points to an array or a single object are two different, unrelated things. In other words, if there was an operator to infer the size that delete uses it would most certainly have UB if used on non-array allocations, thus it wouldn't allow you to decide whether the pointer is to an array allocation or not.

        – Max Langhof
        Feb 20 at 11:45








      • 2





        @MichelePiccolini You shouldn't really be using delete or delete at all, though; that's for the insides of containers and smart pointers, which do have all this information nicely tucked away.

        – Lightness Races in Orbit
        Feb 20 at 11:57






      • 2





        It might not know exactly, it might only know the size of the block it chose, which might tell it the size rounded up to the next multiple of 16 bytes, for example. Depending on the allocator of course. xD, @Handy999 already posted this as an answer before I commented.

        – Peter Cordes
        Feb 20 at 17:38
















      25












      25








      25







      It does - the allocator, or some implementation detail behind it, knows exactly what the size of the block is.



      But that information is not provided to you or to the "code layer" of your program.



      Could the language have been designed to do this? Sure! It's probably a case of "don't pay for what you don't use" — it's your responsibility to remember this information. After all, you know how much memory you asked for! Often times people will not want the cost of a number being passed up the call stack when, most of the time, they won't need it to be.



      There are some platform-specific "extensions" that may get you what you want, like malloc_usable_size on Linux and _msize on Windows, though these assume that your allocator used malloc and didn't do any other magic that may extend the size of the allocated block at the lowest level. I'd say you're still better off tracking this yourself if you really need it… or using a vector.






      share|improve this answer















      It does - the allocator, or some implementation detail behind it, knows exactly what the size of the block is.



      But that information is not provided to you or to the "code layer" of your program.



      Could the language have been designed to do this? Sure! It's probably a case of "don't pay for what you don't use" — it's your responsibility to remember this information. After all, you know how much memory you asked for! Often times people will not want the cost of a number being passed up the call stack when, most of the time, they won't need it to be.



      There are some platform-specific "extensions" that may get you what you want, like malloc_usable_size on Linux and _msize on Windows, though these assume that your allocator used malloc and didn't do any other magic that may extend the size of the allocated block at the lowest level. I'd say you're still better off tracking this yourself if you really need it… or using a vector.







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Feb 20 at 10:28

























      answered Feb 20 at 10:19









      Lightness Races in OrbitLightness Races in Orbit

      292k52475808




      292k52475808








      • 4





        @MaxLanghof "If I have to keep track of it, then I have to pay extra at some point" The key word is if.

        – Lightness Races in Orbit
        Feb 20 at 10:26






      • 4





        @MaxLanghof Admittedly I would be vaguely interested in finding out whether there's some crucial reason that this wasn't made part of the stdlib's allocation interface(s), that go beyond "we cba and don't think you should need this"

        – Lightness Races in Orbit
        Feb 20 at 10:32






      • 1





        @MichelePiccolini The first question in your comment is unrelated to the topic at hand - correctly deleteing a pointer to an array if you already know it is a pointer to an array and being able to infer whether a pointer points to an array or a single object are two different, unrelated things. In other words, if there was an operator to infer the size that delete uses it would most certainly have UB if used on non-array allocations, thus it wouldn't allow you to decide whether the pointer is to an array allocation or not.

        – Max Langhof
        Feb 20 at 11:45








      • 2





        @MichelePiccolini You shouldn't really be using delete or delete at all, though; that's for the insides of containers and smart pointers, which do have all this information nicely tucked away.

        – Lightness Races in Orbit
        Feb 20 at 11:57






      • 2





        It might not know exactly, it might only know the size of the block it chose, which might tell it the size rounded up to the next multiple of 16 bytes, for example. Depending on the allocator of course. xD, @Handy999 already posted this as an answer before I commented.

        – Peter Cordes
        Feb 20 at 17:38
















      • 4





        @MaxLanghof "If I have to keep track of it, then I have to pay extra at some point" The key word is if.

        – Lightness Races in Orbit
        Feb 20 at 10:26






      • 4





        @MaxLanghof Admittedly I would be vaguely interested in finding out whether there's some crucial reason that this wasn't made part of the stdlib's allocation interface(s), that go beyond "we cba and don't think you should need this"

        – Lightness Races in Orbit
        Feb 20 at 10:32






      • 1





        @MichelePiccolini The first question in your comment is unrelated to the topic at hand - correctly deleteing a pointer to an array if you already know it is a pointer to an array and being able to infer whether a pointer points to an array or a single object are two different, unrelated things. In other words, if there was an operator to infer the size that delete uses it would most certainly have UB if used on non-array allocations, thus it wouldn't allow you to decide whether the pointer is to an array allocation or not.

        – Max Langhof
        Feb 20 at 11:45








      • 2





        @MichelePiccolini You shouldn't really be using delete or delete at all, though; that's for the insides of containers and smart pointers, which do have all this information nicely tucked away.

        – Lightness Races in Orbit
        Feb 20 at 11:57






      • 2





        It might not know exactly, it might only know the size of the block it chose, which might tell it the size rounded up to the next multiple of 16 bytes, for example. Depending on the allocator of course. xD, @Handy999 already posted this as an answer before I commented.

        – Peter Cordes
        Feb 20 at 17:38










      4




      4





      @MaxLanghof "If I have to keep track of it, then I have to pay extra at some point" The key word is if.

      – Lightness Races in Orbit
      Feb 20 at 10:26





      @MaxLanghof "If I have to keep track of it, then I have to pay extra at some point" The key word is if.

      – Lightness Races in Orbit
      Feb 20 at 10:26




      4




      4





      @MaxLanghof Admittedly I would be vaguely interested in finding out whether there's some crucial reason that this wasn't made part of the stdlib's allocation interface(s), that go beyond "we cba and don't think you should need this"

      – Lightness Races in Orbit
      Feb 20 at 10:32





      @MaxLanghof Admittedly I would be vaguely interested in finding out whether there's some crucial reason that this wasn't made part of the stdlib's allocation interface(s), that go beyond "we cba and don't think you should need this"

      – Lightness Races in Orbit
      Feb 20 at 10:32




      1




      1





      @MichelePiccolini The first question in your comment is unrelated to the topic at hand - correctly deleteing a pointer to an array if you already know it is a pointer to an array and being able to infer whether a pointer points to an array or a single object are two different, unrelated things. In other words, if there was an operator to infer the size that delete uses it would most certainly have UB if used on non-array allocations, thus it wouldn't allow you to decide whether the pointer is to an array allocation or not.

      – Max Langhof
      Feb 20 at 11:45







      @MichelePiccolini The first question in your comment is unrelated to the topic at hand - correctly deleteing a pointer to an array if you already know it is a pointer to an array and being able to infer whether a pointer points to an array or a single object are two different, unrelated things. In other words, if there was an operator to infer the size that delete uses it would most certainly have UB if used on non-array allocations, thus it wouldn't allow you to decide whether the pointer is to an array allocation or not.

      – Max Langhof
      Feb 20 at 11:45






      2




      2





      @MichelePiccolini You shouldn't really be using delete or delete at all, though; that's for the insides of containers and smart pointers, which do have all this information nicely tucked away.

      – Lightness Races in Orbit
      Feb 20 at 11:57





      @MichelePiccolini You shouldn't really be using delete or delete at all, though; that's for the insides of containers and smart pointers, which do have all this information nicely tucked away.

      – Lightness Races in Orbit
      Feb 20 at 11:57




      2




      2





      It might not know exactly, it might only know the size of the block it chose, which might tell it the size rounded up to the next multiple of 16 bytes, for example. Depending on the allocator of course. xD, @Handy999 already posted this as an answer before I commented.

      – Peter Cordes
      Feb 20 at 17:38







      It might not know exactly, it might only know the size of the block it chose, which might tell it the size rounded up to the next multiple of 16 bytes, for example. Depending on the allocator of course. xD, @Handy999 already posted this as an answer before I commented.

      – Peter Cordes
      Feb 20 at 17:38













      5














      I think the reason for this is a confluence of three factors.




      1. C++ has a "you only pay for what you use" culture

      2. C++ started its life as a pre-processor for C and hence had to be built on top of what C offered.

      3. C++ is one of the most widely ported languages around. Features that make life difficult for existing ports are unlikely to get added.


      C allows the programmer to free memory blocks without specifying the size of the memory block to free, but does not provide the programmer with any standard way to access the size of the allocation. Furthermore the actual amount of memory allocated may well be larger than the amount the programmer asked for.



      Following the principle of "you only pay for what you use", C++ implementations implement new differently for different types. Typically they only store the size if it is necessary to do so, usually because the type has a non-trivial destructor.



      So while yes, enough information is stored to free the memory block, it would be very difficult to define a sane and portable API for accessing that information. Depending on the data type and platform, the actual requested size may be available (for types where the C++ implementation has to store it), only the actual allocated size may be available (for types where the C++ implementation does not have to store it on platforms where the underlying memory manager has an extension to get the allocated size), or the size may not be available at all (for types where the C++ implementation does not have to store it on platforms that don't provide access to the information from the underlying memory manager).






      share|improve this answer






























        5














        I think the reason for this is a confluence of three factors.




        1. C++ has a "you only pay for what you use" culture

        2. C++ started its life as a pre-processor for C and hence had to be built on top of what C offered.

        3. C++ is one of the most widely ported languages around. Features that make life difficult for existing ports are unlikely to get added.


        C allows the programmer to free memory blocks without specifying the size of the memory block to free, but does not provide the programmer with any standard way to access the size of the allocation. Furthermore the actual amount of memory allocated may well be larger than the amount the programmer asked for.



        Following the principle of "you only pay for what you use", C++ implementations implement new differently for different types. Typically they only store the size if it is necessary to do so, usually because the type has a non-trivial destructor.



        So while yes, enough information is stored to free the memory block, it would be very difficult to define a sane and portable API for accessing that information. Depending on the data type and platform, the actual requested size may be available (for types where the C++ implementation has to store it), only the actual allocated size may be available (for types where the C++ implementation does not have to store it on platforms where the underlying memory manager has an extension to get the allocated size), or the size may not be available at all (for types where the C++ implementation does not have to store it on platforms that don't provide access to the information from the underlying memory manager).






        share|improve this answer




























          5












          5








          5







          I think the reason for this is a confluence of three factors.




          1. C++ has a "you only pay for what you use" culture

          2. C++ started its life as a pre-processor for C and hence had to be built on top of what C offered.

          3. C++ is one of the most widely ported languages around. Features that make life difficult for existing ports are unlikely to get added.


          C allows the programmer to free memory blocks without specifying the size of the memory block to free, but does not provide the programmer with any standard way to access the size of the allocation. Furthermore the actual amount of memory allocated may well be larger than the amount the programmer asked for.



          Following the principle of "you only pay for what you use", C++ implementations implement new differently for different types. Typically they only store the size if it is necessary to do so, usually because the type has a non-trivial destructor.



          So while yes, enough information is stored to free the memory block, it would be very difficult to define a sane and portable API for accessing that information. Depending on the data type and platform, the actual requested size may be available (for types where the C++ implementation has to store it), only the actual allocated size may be available (for types where the C++ implementation does not have to store it on platforms where the underlying memory manager has an extension to get the allocated size), or the size may not be available at all (for types where the C++ implementation does not have to store it on platforms that don't provide access to the information from the underlying memory manager).






          share|improve this answer















          I think the reason for this is a confluence of three factors.




          1. C++ has a "you only pay for what you use" culture

          2. C++ started its life as a pre-processor for C and hence had to be built on top of what C offered.

          3. C++ is one of the most widely ported languages around. Features that make life difficult for existing ports are unlikely to get added.


          C allows the programmer to free memory blocks without specifying the size of the memory block to free, but does not provide the programmer with any standard way to access the size of the allocation. Furthermore the actual amount of memory allocated may well be larger than the amount the programmer asked for.



          Following the principle of "you only pay for what you use", C++ implementations implement new differently for different types. Typically they only store the size if it is necessary to do so, usually because the type has a non-trivial destructor.



          So while yes, enough information is stored to free the memory block, it would be very difficult to define a sane and portable API for accessing that information. Depending on the data type and platform, the actual requested size may be available (for types where the C++ implementation has to store it), only the actual allocated size may be available (for types where the C++ implementation does not have to store it on platforms where the underlying memory manager has an extension to get the allocated size), or the size may not be available at all (for types where the C++ implementation does not have to store it on platforms that don't provide access to the information from the underlying memory manager).







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Feb 20 at 19:01









          Toby Speight

          16.9k134265




          16.9k134265










          answered Feb 20 at 15:06









          plugwashplugwash

          4,5361226




          4,5361226























              1














              This answer applies to Microsoft Visual Studio only.



              There is a function called _msize, which will return the malloced / calloced / realloced size of a pointer.



              It can be found in the malloc.h header, and the parameters are:



              size_t _msize(
              void *memblock
              );


              I am not sure if there is an equivalent in gcc. There probably should be.






              share|improve this answer



















              • 1





                Ahh there is malloc_usable_size() for linux.

                – Owl
                Feb 20 at 10:42











              • Do you know if those are reliable or what could be some cases that might arise and might make the usage of these non reliable?

                – Michele Piccolini
                Feb 20 at 11:01






              • 2





                Well one of the things I noticed when I tested it, I called a malloc on an array of chars 25 long, then called malloc_usable_size on the array. It reported 40 bytes used. This suggests to me that it's actually reporting the container size allocated that is large enough to contain the array.

                – Owl
                Feb 20 at 14:37
















              1














              This answer applies to Microsoft Visual Studio only.



              There is a function called _msize, which will return the malloced / calloced / realloced size of a pointer.



              It can be found in the malloc.h header, and the parameters are:



              size_t _msize(
              void *memblock
              );


              I am not sure if there is an equivalent in gcc. There probably should be.






              share|improve this answer



















              • 1





                Ahh there is malloc_usable_size() for linux.

                – Owl
                Feb 20 at 10:42











              • Do you know if those are reliable or what could be some cases that might arise and might make the usage of these non reliable?

                – Michele Piccolini
                Feb 20 at 11:01






              • 2





                Well one of the things I noticed when I tested it, I called a malloc on an array of chars 25 long, then called malloc_usable_size on the array. It reported 40 bytes used. This suggests to me that it's actually reporting the container size allocated that is large enough to contain the array.

                – Owl
                Feb 20 at 14:37














              1












              1








              1







              This answer applies to Microsoft Visual Studio only.



              There is a function called _msize, which will return the malloced / calloced / realloced size of a pointer.



              It can be found in the malloc.h header, and the parameters are:



              size_t _msize(
              void *memblock
              );


              I am not sure if there is an equivalent in gcc. There probably should be.






              share|improve this answer













              This answer applies to Microsoft Visual Studio only.



              There is a function called _msize, which will return the malloced / calloced / realloced size of a pointer.



              It can be found in the malloc.h header, and the parameters are:



              size_t _msize(
              void *memblock
              );


              I am not sure if there is an equivalent in gcc. There probably should be.







              share|improve this answer












              share|improve this answer



              share|improve this answer










              answered Feb 20 at 10:25









              OwlOwl

              656511




              656511








              • 1





                Ahh there is malloc_usable_size() for linux.

                – Owl
                Feb 20 at 10:42











              • Do you know if those are reliable or what could be some cases that might arise and might make the usage of these non reliable?

                – Michele Piccolini
                Feb 20 at 11:01






              • 2





                Well one of the things I noticed when I tested it, I called a malloc on an array of chars 25 long, then called malloc_usable_size on the array. It reported 40 bytes used. This suggests to me that it's actually reporting the container size allocated that is large enough to contain the array.

                – Owl
                Feb 20 at 14:37














              • 1





                Ahh there is malloc_usable_size() for linux.

                – Owl
                Feb 20 at 10:42











              • Do you know if those are reliable or what could be some cases that might arise and might make the usage of these non reliable?

                – Michele Piccolini
                Feb 20 at 11:01






              • 2





                Well one of the things I noticed when I tested it, I called a malloc on an array of chars 25 long, then called malloc_usable_size on the array. It reported 40 bytes used. This suggests to me that it's actually reporting the container size allocated that is large enough to contain the array.

                – Owl
                Feb 20 at 14:37








              1




              1





              Ahh there is malloc_usable_size() for linux.

              – Owl
              Feb 20 at 10:42





              Ahh there is malloc_usable_size() for linux.

              – Owl
              Feb 20 at 10:42













              Do you know if those are reliable or what could be some cases that might arise and might make the usage of these non reliable?

              – Michele Piccolini
              Feb 20 at 11:01





              Do you know if those are reliable or what could be some cases that might arise and might make the usage of these non reliable?

              – Michele Piccolini
              Feb 20 at 11:01




              2




              2





              Well one of the things I noticed when I tested it, I called a malloc on an array of chars 25 long, then called malloc_usable_size on the array. It reported 40 bytes used. This suggests to me that it's actually reporting the container size allocated that is large enough to contain the array.

              – Owl
              Feb 20 at 14:37





              Well one of the things I noticed when I tested it, I called a malloc on an array of chars 25 long, then called malloc_usable_size on the array. It reported 40 bytes used. This suggests to me that it's actually reporting the container size allocated that is large enough to contain the array.

              – Owl
              Feb 20 at 14:37











              -1














              If delete doesn't have to know the size of the array at the time it is called, your entire argument falls apart. And delete doesn't have to know the size of the array at the time it is called. It only needs to know the size to make the block available for use by others, and absolutely nothing requires it to make the block available for use by others at the time delete is called.



              For example, delete my dice a large block into some number of smaller blocks. Each of those blocks but one need only have a pointer to the control block that knows the size. If any block but the control block is passed to delete first, then delete has no idea how big the block that was just freed is and won't know until later.



              That it is not absolutely required that delete know the size of a block at every arbitrary point during its lifetime is sufficient to invalidate your argument.






              share|improve this answer




























                -1














                If delete doesn't have to know the size of the array at the time it is called, your entire argument falls apart. And delete doesn't have to know the size of the array at the time it is called. It only needs to know the size to make the block available for use by others, and absolutely nothing requires it to make the block available for use by others at the time delete is called.



                For example, delete my dice a large block into some number of smaller blocks. Each of those blocks but one need only have a pointer to the control block that knows the size. If any block but the control block is passed to delete first, then delete has no idea how big the block that was just freed is and won't know until later.



                That it is not absolutely required that delete know the size of a block at every arbitrary point during its lifetime is sufficient to invalidate your argument.






                share|improve this answer


























                  -1












                  -1








                  -1







                  If delete doesn't have to know the size of the array at the time it is called, your entire argument falls apart. And delete doesn't have to know the size of the array at the time it is called. It only needs to know the size to make the block available for use by others, and absolutely nothing requires it to make the block available for use by others at the time delete is called.



                  For example, delete my dice a large block into some number of smaller blocks. Each of those blocks but one need only have a pointer to the control block that knows the size. If any block but the control block is passed to delete first, then delete has no idea how big the block that was just freed is and won't know until later.



                  That it is not absolutely required that delete know the size of a block at every arbitrary point during its lifetime is sufficient to invalidate your argument.






                  share|improve this answer













                  If delete doesn't have to know the size of the array at the time it is called, your entire argument falls apart. And delete doesn't have to know the size of the array at the time it is called. It only needs to know the size to make the block available for use by others, and absolutely nothing requires it to make the block available for use by others at the time delete is called.



                  For example, delete my dice a large block into some number of smaller blocks. Each of those blocks but one need only have a pointer to the control block that knows the size. If any block but the control block is passed to delete first, then delete has no idea how big the block that was just freed is and won't know until later.



                  That it is not absolutely required that delete know the size of a block at every arbitrary point during its lifetime is sufficient to invalidate your argument.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Feb 21 at 1:24









                  David SchwartzDavid Schwartz

                  138k14144226




                  138k14144226















                      Popular posts from this blog

                      Biblatex bibliography style without URLs when DOI exists (in Overleaf with Zotero bibliography)

                      ComboBox Display Member on multiple fields

                      Is it possible to collect Nectar points via Trainline?