Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>It is definitely not safe as you can simply try out with the following code:</p> <pre><code>#include&lt;iostream&gt; class test { public: test(){ std::cout &lt;&lt; "Constructor" &lt;&lt; std::endl; } ~test(){ std::cout &lt;&lt; "Destructor" &lt;&lt; std::endl; } }; int main() { test * t = new test[ 10 ]; delete t; return 1; } </code></pre> <p>Have a look at <a href="http://ideone.com/b8BiQ" rel="nofollow">http://ideone.com/b8BiQ</a> . It fails misserably.</p> <p>It may work when you do not use classes, but only fundamental types, but even that is not guaranteed.</p> <p><strong>EDIT</strong>: Some explanations for those of you who want to know <em>why</em> this crashes:</p> <p><code>new</code> and <code>delete</code> mainly serve as wrappers around <code>malloc()</code>, hence calling <code>free()</code> on a newed pointer is most of the time "safe" (remember to call the destructor), but you should not rely on it. For <code>new[]</code> and <code>delete[]</code> however the situation is more complicated.</p> <p>When an array of classes gets constructed using <code>new[]</code> each default constructor will be called in turn. When you do <code>delete[]</code> each destructor gets called. However each destructor also has to be supplied a <code>this</code> pointer to use inside as a hidden parameter. So before calling the destructor the program has to find the locations of all objects within the reserved memory, to pass these locations as <code>this</code> pointers to the destructor. So all information that is later needed to reconstruct this information needs to be stored somewhere.</p> <p>Now the easiest way would be to have a global map somewhere around, which stores this information for all <code>new[]</code>ed pointers. In this case if you <code>delete</code> is called instead of <code>delete[]</code> only one of the destructors would be called and the entry would not be removed from a map. However this method is usually not used, because maps are slow and memory management should be as fast as possible.</p> <p>Hence for the stdlibc++ a different solution is used. Since only a few bytes are needed as additional information, it is the fastest to just over-allocate by these few bytes, store the information at the beginning of the memory and return the pointer to the memory after the bookkeeping. So if you allocate an array of 10 objects of 10 bytes each, the programm will allocate <code>100+X</code> bytes where <code>X</code> is the size of the data which is needed to reconstruct the this.</p> <p>So in this case it looks something like this</p> <pre><code>| Bookkeeping | First Object | Second Object |.... ^ ^ | This is what is returned by new[] | this is what is returned by malloc() </code></pre> <p>So in case you pass the pointer you have recieved from <code>new[]</code> to <code>delete[]</code> it will call all destructors, then substract <code>X</code> from the pointer and give that one to <code>free()</code>. However if you call <code>delete</code> instead, it will call a destructor for the first object and then immediately pass that pointer to <code>free()</code>, which means <code>free()</code> has just been passed a pointer which was never malloced, which means the result is UB.</p> <p>Have a look at <a href="http://ideone.com/tIiMw" rel="nofollow">http://ideone.com/tIiMw</a> , to see what gets passed to <code>delete</code> and <code>delete[]</code>. As you can see, the pointer returned from <code>new[]</code> is not the pointer which was allocated inside, but 4 is added to it before it is being returned to <code>main()</code>. When calling <code>delete[]</code> correctly the same four is substracted an we get the correct pointer within <code>delete[]</code> however this substraction is missing when calling <code>delete</code> and we get the wrong pointer.</p> <p>In case of calling <code>new[]</code> on a fundamental type, the compiler immediately knows that it will not have to call any destructors later and it just optimizes the bookkeeping away. However it is definitely allowed to write bookkeeping even for fundamental types. And it is also allowed to add bookkeeping in case you call <code>new</code>.</p> <p>This bookkeeping in front of the real pointer is actually a very good trick, in case you ever need to write your own memory allocation routines as a replacement of <code>new</code> and <code>delete</code>. There is hardly any limit on what you can store there , so one should never assume that anything returned from <code>new</code> or <code>new[]</code> was actually returned from <code>malloc()</code>.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload