{"id":40763,"date":"2004-02-03T07:00:00","date_gmt":"2004-02-03T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2004\/02\/03\/mismatching-scalar-and-vector-new-and-delete\/"},"modified":"2004-02-03T07:00:00","modified_gmt":"2004-02-03T07:00:00","slug":"mismatching-scalar-and-vector-new-and-delete","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20040203-00\/?p=40763","title":{"rendered":"Mismatching scalar and vector new and delete"},"content":{"rendered":"<p><a HREF=\"http:\/\/weblogs.asp.net\/oldnewthing\/archive\/2004\/01\/30\/65013.aspx\">\nIn a previous entry<\/a> I alluded to the problems that\ncan occur if you mismatch scalar &#8220;new&#8221; with vector &#8220;delete[]&#8221;\nor vice versa.<\/p>\n<p>\nThere is a nice description of C++ memory management\nin\n<a HREF=\"http:\/\/www.informit.com\/isapi\/product_id~{4F6C1FE6-59E8-48BF-BB67-979C052EA7B8}\/content\/index.asp\">\nC++ Gotchas: Avoiding Common Problems in Coding and Design<\/a>\non\n<a HREF=\"http:\/\/www.informit.com\">www.informit.com<\/a>,\nand I encourage you to read\nat least the section titled\n<a HREF=\"http:\/\/www.informit.com\/isapi\/product_id~{63BFBFF1-1E0E-466F-8E1A-D4AD830C2455}\/content\/index.asp\">\nFailure to Distinguish Scalar and Array Allocation<\/a>\nbefore continuing with this entry,\nbecause I&#8217;m going to use that information as\na starting point.\n<\/p>\n<p>\nHere&#8217;s how the Microsoft C++ compiler manages vector allocation.\nNote that this is internal implementation detail, so it&#8217;s subject\nto change at any time, but knowing this may give a better insight\ninto why mixing scalar and vector new\/delete is a bad thing.\n<\/p>\n<p>\nThe important thing to note is that when you do a scalar\n&#8220;delete p&#8221;, you are telling the compiler, &#8220;p points to a single\nobject.&#8221;  The compiler will call the destructor once, namely\nfor the object you are destructing.\n<\/p>\n<p>\nWhen you do &#8220;delete[] p&#8221;, you are saying,\n&#8220;p points to a bunch of objects, but I&#8217;m not telling you how many.&#8221;\nIn this case, the compiler needs to generate extra code to keep\ntrack of how many it needs to destruct. This extra information\nis kept in a &#8220;secret place&#8221; when the vector is allocated with\n&#8220;new[]&#8221;.\n<\/p>\n<p>\nLet&#8217;s watch this in action:<\/p>\n<pre>\nclass MyClass {\npublic:\n  MyClass(); \/\/ constructor\n  ~MyClass(); \/\/ destructor\n  int i;\n};\nMyClass *allocate_stuff(int howmany)\n{\n    return new MyClass[howmany];\n}\n<\/pre>\n<p>\nThe generated code for the &#8220;allocate_stuff&#8221; function\nlooks like this:\n<\/p>\n<pre>\n    push    esi\n    mov     esi, [esp+8] ; howmany\n   ;  eax = howmany * sizeof(MyClass) + sizeof(size_t)\n    lea     eax, [esi*4+4]\n    push    eax\n    call    operator new\n    test    eax, eax\n    pop     ecx\n    je      fail\n    push    edi\n    push    OFFSET MyClass::MyClass\n    push    esi\n    lea     edi, [eax+4] ; edi = eax + sizeof(size_t)\n    push    4 ; sizeof(MyClass)\n    push    edi\n    mov     [eax], esi ; howmany\n    call    `vector constructor iterator'\n    mov     eax, edi\n    pop     edi\n    jmp     done\nfail:\n    xor     eax, eax\ndone:\n    pop     esi\n    retd    4\n<\/pre>\n<p>\nTranslated back into pseudo-C++, the code looks like this:\n<\/p>\n<pre>\nMyClass* allocate_stuff(int howmany)\n{\n  void *p = operator new(\n     howmany * sizeof(MyClass) + sizeof(size_t));\n  if (p) {\n    size_t* a = reinterpret_cast&lt;size_t*&gt;(p);\n    *a++ = howmany;\n    vector constructor iterator(a,\n      sizeof(MyClass), &amp;MyClass::MyClass);\n    return reinterpret_cast&lt;MyClass*&gt;(a);\n  }\n  return NULL;\n}\n<\/pre>\n<p>\nIn other words, the memory layout of the vector of\nMyClass objects looks like this:\n<\/p>\n<table BORDER=\"0\">\n<col ALIGN=\"center\">\n<tr>\n<tr>\n<td STYLE=\"border: solid 1px buttonshadow\">howmany<\/td>\n<\/tr>\n<tr>\n<td STYLE=\"border: solid 1px buttonshadow;height: 4em\">MyClass[0]<\/td>\n<\/tr>\n<tr>\n<td STYLE=\"border: solid 1px buttonshadow;height: 4em\">MyClass[1]<\/td>\n<\/tr>\n<tr>\n<td>&#8230;<\/td>\n<\/tr>\n<tr>\n<td STYLE=\"border: solid 1px buttonshadow;height: 4em\">MyClass[howmany-1]<\/td>\n<\/tr>\n<\/table>\n<p>\nThe pointer returned by the new[] operator\nis <b>not<\/b> the start of the\nallocated memory but rather points to MyClass[0]. The count of\nelements is hidden in front of the vector.\n<\/p>\n<p>\nThe deletion of a vector performs this operation in reverse:<\/p>\n<pre>\nvoid free_stuff(MyClass* p)\n{\n    delete[] p;\n}\n<\/pre>\n<p>generates<\/p>\n<pre>\n    mov     ecx, [esp+4] ; p\n    test    ecx, ecx\n    je      skip\n    push    3\n    call    MyClass::`vector deleting destructor`\nskip\n    ret     4\n<\/pre>\n<p>Translated back into pseudo-C++, the code looks like this:<\/p>\n<pre>\nvoid free_stuff(MyClass* p)\n{\n  if (p) p-&gt;vector deleting destructor(3);\n}\n<\/pre>\n<p>The vector deleting destructor goes like this (pseudo-code):<\/p>\n<pre>\nvoid MyClass::vector deleting destructor(int flags)\n{\n  if (flags &amp; 2) { \/\/ if vector destruct\n    size_t* a = reinterpret_cast&lt;size_t*&gt;(this) - 1;\n    size_t howmany = *a;\n    vector destructor iterator(p, sizeof(MyClass),\n      howmany, MyClass::~MyClass);\n    if (flags &amp; 1) { \/\/ if delete too\n      operator delete(a);\n    }\n  } else { \/\/ else scalar destruct\n    this-&gt;~MyClass(); \/\/ destruct one\n    if (flags &amp; 1) { \/\/ if delete too\n      operator delete(this);\n    }\n  }\n}\n<\/pre>\n<p>\nThe vector deleting destructor takes some flags. If 2 is set,\nthen a vector is being destructed; otherwise a single object is\nbeing destructed. If 1 is set, then the memory is also freed.\n<\/p>\n<p>\nIn our case, the flags parameter is 3, so we will perform\na vector destruct followed by a delete. Observe that this\ncode sucks the original &#8220;howmany&#8221; value out of its secret\nhiding place and asks the vector destructor iterator to\nrun the destructor that many times before freeing the memory.\n<\/p>\n<p>\nSo now, armed with this information, you should be able to\ndescribe what happens if you allocate memory with scalar &#8220;new&#8221;\nand free it with vector &#8220;delete[]&#8221; or vice versa.\n<\/p>\n<p>\nBonus exercise: What optimizations can be performed if the\ndestructor MyClass::~MyClass() is removed from the class\ndefinition?\n<\/p>\n<p>\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2004\/02\/04\/67384.aspx\">\nAnswers to come tomorrow<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In a previous entry I alluded to the problems that can occur if you mismatch scalar &#8220;new&#8221; with vector &#8220;delete[]&#8221; or vice versa. There is a nice description of C++ memory management in C++ Gotchas: Avoiding Common Problems in Coding and Design on www.informit.com, and I encourage you to read at least the section titled [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-40763","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>In a previous entry I alluded to the problems that can occur if you mismatch scalar &#8220;new&#8221; with vector &#8220;delete[]&#8221; or vice versa. There is a nice description of C++ memory management in C++ Gotchas: Avoiding Common Problems in Coding and Design on www.informit.com, and I encourage you to read at least the section titled [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/40763","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=40763"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/40763\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=40763"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=40763"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=40763"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}