{"id":31083,"date":"2006-05-24T10:00:12","date_gmt":"2006-05-24T10:00:12","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2006\/05\/24\/beware-the-c-implicit-conversion\/"},"modified":"2006-05-24T10:00:12","modified_gmt":"2006-05-24T10:00:12","slug":"beware-the-c-implicit-conversion","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20060524-12\/?p=31083","title":{"rendered":"Beware the C++ implicit conversion"},"content":{"rendered":"<p>\nToday&#8217;s topic was inspired by a question from a customer:\n<\/p>\n<blockquote CLASS=\"q\"><p>\nI am working on a stack overflow bug.\nTo reduce the size of the stack frame,\nI removed as many local variables as I could,\nbut there&#8217;s still a a lot of stack space that I can&#8217;t\naccount for.\nWhat else lives on the stack aside from local variables,\nparameters, saved registers, and the return address?\n<\/p><\/blockquote>\n<p>\nWell, there&#8217;s also structured exception handling information,\nbut that&#8217;s typically not too much and therefore wouldn&#8217;t\nbe the source of &#8220;a lot&#8221; of mysterious stack usage.\n<\/p>\n<p>\nMy guess is that the code is generating lots of large C++ temporaries.\nConsider the following program fragment:\n<\/p>\n<pre>\nclass BigBuffer\n{\npublic:\n BigBuffer(int initialValue)\n   { memset(buffer, initialValue, sizeof(buffer)); }\nprivate:\n char buffer[65536];\n};\nextern void Foo(const BigBuffer&amp; o);\nvoid oops()\n{\n Foo(3);\n}\n<\/pre>\n<p>\n&#8220;How does this code even compile?\nThe function <code>Foo<\/code> wants a <code>BigBuffer<\/code>,\nnot an integer!&#8221;\nYet compile it does.\n<\/p>\n<p>\nThat&#8217;s because the compiler is using the <code>BigBuffer<\/code>\nconstructor as a converter.\nIn other words, the compiler inserted the following temporary\nvariable:\n<\/p>\n<pre>\nvoid oops()\n{\n BigBuffer temp(3);\n Foo(temp);\n}\n<\/pre>\n<p>\nIt did this because a constructor that takes exactly one argument\nserves two purposes:\nIt can be used as a traditional constructor (as we saw with\n<code>BigBuffer temp(3)<\/code>)\nor it can be used to provide an implicit conversion from the\nargument type to the constructed type.\nIn this case, the <code>BigBuffer(int)<\/code> constructor is\nbeing used as a conversion from <code>int<\/code> to <code>BigBuffer<\/code>.\n<\/p>\n<p>\nTo prevent this from happening, use the <code>explicit<\/code> keyword:\n<\/p>\n<pre>\nclass BigBuffer\n{\npublic:\n <font COLOR=\"blue\">explicit<\/font> BigBuffer(int initialValue)\n   { memset(buffer, initialValue, sizeof(buffer)); }\nprivate:\n char buffer[65536];\n};\n<\/pre>\n<p>\nWith this change, the call to <code>Foo(3)<\/code> raises a\ncompiler error:\n<\/p>\n<pre>\nsample.cpp: error C2664: 'Foo' : cannot convert parameter 1 from\n     'int' to 'const BigBuffer &amp;'\n     Reason: cannot convert from 'int' to 'const BigBuffer'\n     Constructor for class 'BigBuffer' is declared 'explicit'\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Today&#8217;s topic was inspired by a question from a customer: I am working on a stack overflow bug. To reduce the size of the stack frame, I removed as many local variables as I could, but there&#8217;s still a a lot of stack space that I can&#8217;t account for. What else lives on the stack [&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-31083","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Today&#8217;s topic was inspired by a question from a customer: I am working on a stack overflow bug. To reduce the size of the stack frame, I removed as many local variables as I could, but there&#8217;s still a a lot of stack space that I can&#8217;t account for. What else lives on the stack [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/31083","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=31083"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/31083\/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=31083"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=31083"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=31083"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}