{"id":110619,"date":"2024-12-09T07:00:00","date_gmt":"2024-12-09T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=110619"},"modified":"2024-12-09T10:46:23","modified_gmt":"2024-12-09T18:46:23","slug":"20241209-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20241209-00\/?p=110619","title":{"rendered":"Learning to read C++ compiler errors: Failing to create a <CODE>shared_ptr<\/CODE>"},"content":{"rendered":"<p>Consider the following erroneous code:<\/p>\n<pre>#include &lt;memory&gt;\r\n#include &lt;string&gt;\r\n\r\nstruct WidgetOptions\r\n{\r\n    \/\/ imagine there is interesting stuff here\r\n};\r\n\r\nstruct Widget\r\n{\r\n    Widget(WidgetOptions const* options);\r\n\r\n    \/\/ imagine there is other interesting stuff here\r\n};\r\n\r\nvoid oops()\r\n{\r\n    WidgetOptions options;\r\n\r\n    \/\/ The next line fails to compile\r\n    std::shared_ptr&lt;Widget&gt; widget =\r\n        std::make_shared&lt;Widget&gt;(options);\r\n}\r\n<\/pre>\n<p>Here comes the error explosion.<\/p>\n<pre style=\"white-space: pre-wrap;\">\/\/ gcc\r\nIn file included from bits\/stl_tempbuf.h:61,\r\n                 from memory:66,\r\n                 from sample.cpp:1:\r\nbits\/stl_construct.h: In instantiation of 'void std::_Construct(_Tp*, _Args&amp;&amp; ...) [with _Tp = Widget; _Args = {WidgetOptions&amp;}]':\r\nbits\/alloc_traits.h:657:19:   required from 'static void std::allocator_traits&lt;std::allocator&lt;void&gt; &gt;::construct(allocator_type&amp;, _Up*, _Args&amp;&amp; ...) [with _Up = Widget; _Args = {WidgetOptions&amp;}; allocator_type = std::allocator&lt;void&gt;]'\r\n  657 |         { std::_Construct(__p, std::forward&lt;_Args&gt;(__args)...); }\r\n      |           ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\nbits\/shared_ptr_base.h:607:39:   required from 'std::_Sp_counted_ptr_inplace&lt;_Tp, _Alloc, _Lp&gt;::_Sp_counted_ptr_inplace(_Alloc, _Args&amp;&amp; ...) [with _Args = {WidgetOptions&amp;}; _Tp = Widget; _Alloc = std::allocator&lt;void&gt;; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]'\r\n  607 |           allocator_traits&lt;_Alloc&gt;::construct(__a, _M_ptr(),\r\n      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~\r\n  608 |               std::forward&lt;_Args&gt;(__args)...); \/\/ might throw\r\n      |               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \r\nbits\/shared_ptr_base.h:969:16:   required from 'std::__shared_count&lt;_Lp&gt;::__shared_count(_Tp*&amp;, std::_Sp_alloc_shared_tag&lt;_Alloc&gt;, _Args&amp;&amp; ...) [with _Tp = Widget; _Alloc = std::allocator&lt;void&gt;; _Args = {WidgetOptions&amp;}; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]'\r\n  969 |           auto __pi = ::new (__mem)\r\n      |                       ^~~~~~~~~~~~~\r\n  970 |             _Sp_cp_type(__a._M_a, std::forward&lt;_Args&gt;(__args)...);\r\n      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\nbits\/shared_ptr_base.h:1713:14:   required from 'std::__shared_ptr&lt;_Tp, _Lp&gt;::__shared_ptr(std::_Sp_alloc_shared_tag&lt;_Tp&gt;, _Args&amp;&amp; ...) [with _Alloc = std::allocator&lt;void&gt;; _Args = {WidgetOptions&amp;}; _Tp = Widget; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]'\r\n 1713 |         : _M_ptr(), _M_refcount(_M_ptr, __tag, std::forward&lt;_Args&gt;(__args)...)\r\n      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\nbits\/shared_ptr.h:463:59:   required from 'std::shared_ptr&lt;_Tp&gt;::shared_ptr(std::_Sp_alloc_shared_tag&lt;_Tp&gt;, _Args&amp;&amp; ...) [with _Alloc = std::allocator&lt;void&gt;; _Args = {WidgetOptions&amp;}; _Tp = Widget]'\r\n  463 |         : __shared_ptr&lt;_Tp&gt;(__tag, std::forward&lt;_Args&gt;(__args)...)\r\n      |                                                                  ^\r\nbits\/shared_ptr.h:1007:14:   required from 'std::shared_ptr&lt;typename std::enable_if&lt;(! std::is_array&lt;_Tp&gt;::value), _Tp&gt;::type&gt; std::make_shared(_Args&amp;&amp; ...) [with _Tp = Widget; _Args = {WidgetOptions&amp;}; typename enable_if&lt;(! is_array&lt;_Tp&gt;::value), _Tp&gt;::type = Widget]'\r\n 1007 |       return shared_ptr&lt;_Tp&gt;(_Sp_alloc_shared_tag&lt;_Alloc&gt;{__a},\r\n      |              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n 1008 |                              std::forward&lt;_Args&gt;(__args)...);\r\n      |                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\nsample.cpp:22:33:   required from here\r\n   22 |         std::make_shared&lt;Widget&gt;(options);\r\n      |         ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~\r\nbits\/stl_construct.h:119:7: error: no matching function for call to 'Widget::Widget(WidgetOptions&amp;)'\r\n  119 |       ::new((void*)__p) _Tp(std::forward&lt;_Args&gt;(__args)...);\r\n      |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\nsample.cpp:11:5: note: candidate: 'Widget::Widget(const WidgetOptions*)'\r\n   11 |     Widget(WidgetOptions const* options);\r\n      |     ^~~~~~\r\nsample.cpp:11:33: note:   no known conversion for argument 1 from 'WidgetOptions' to 'const WidgetOptions*'\r\n   11 |     Widget(WidgetOptions const* options);\r\n      |            ~~~~~~~~~~~~~~~~~~~~~^~~~~~~\r\nsample.cpp:9:8: note: candidate: 'constexpr Widget::Widget(const Widget&amp;)'\r\n    9 | struct Widget\r\n      |        ^~~~~~\r\nsample.cpp:9:8: note:   no known conversion for argument 1 from 'WidgetOptions' to 'const Widget&amp;'\r\nsample.cpp:9:8: note: candidate: 'constexpr Widget::Widget(Widget&amp;&amp;)'\r\nsample.cpp:9:8: note:   no known conversion for argument 1 from 'WidgetOptions' to 'Widget&amp;&amp;'\r\nCompiler returned: 1\r\n<\/pre>\n<p>And for clang:<\/p>\n<pre style=\"white-space: pre-wrap;\">In file included from sample.cpp:1:\r\nIn file included from memory:66:\r\nIn file included from bits\/stl_tempbuf.h:61:\r\nbits\/stl_construct.h:119:25: error: no matching constructor for initialization of 'Widget'\r\n  119 |       ::new((void*)__p) _Tp(std::forward&lt;_Args&gt;(__args)...);\r\n      |                         ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\nbits\/alloc_traits.h:657:9: note: in instantiation of function template specialization 'std::_Construct&lt;Widget, WidgetOptions &amp;&gt;' requested here\r\n  657 |         { std::_Construct(__p, std::forward&lt;_Args&gt;(__args)...); }\r\n      |                ^\r\nbits\/shared_ptr_base.h:607:30: note: in instantiation of function template specialization 'std::allocator_traits&lt;std::allocator&lt;void&gt;&gt;::construct&lt;Widget, WidgetOptions &amp;&gt;' requested here\r\n  607 |           allocator_traits&lt;_Alloc&gt;::construct(__a, _M_ptr(),\r\n      |                                     ^\r\nbits\/shared_ptr_base.h:970:6: note: in instantiation of function template specialization 'std::_Sp_counted_ptr_inplace&lt;Widget, std::allocator&lt;void&gt;, __gnu_cxx::_S_atomic&gt;::_Sp_counted_ptr_inplace&lt;WidgetOptions &amp;&gt;' requested here\r\n  970 |             _Sp_cp_type(__a._M_a, std::forward&lt;_Args&gt;(__args)...);\r\n      |             ^\r\nbits\/shared_ptr_base.h:1713:14: note: in instantiation of function template specialization 'std::__shared_count&lt;&gt;::__shared_count&lt;Widget, std::allocator&lt;void&gt;, WidgetOptions &amp;&gt;' requested here\r\n 1713 |         : _M_ptr(), _M_refcount(_M_ptr, __tag, std::forward&lt;_Args&gt;(__args)...)\r\n      |                     ^\r\nbits\/shared_ptr.h:463:4: note: in instantiation of function template specialization 'std::__shared_ptr&lt;Widget&gt;::__shared_ptr&lt;std::allocator&lt;void&gt;, WidgetOptions &amp;&gt;' requested here\r\n  463 |         : __shared_ptr&lt;_Tp&gt;(__tag, std::forward&lt;_Args&gt;(__args)...)\r\n      |           ^\r\nbits\/shared_ptr.h:1007:14: note: in instantiation of function template specialization 'std::shared_ptr&lt;Widget&gt;::shared_ptr&lt;std::allocator&lt;void&gt;, WidgetOptions &amp;&gt;' requested here\r\n 1007 |       return shared_ptr&lt;_Tp&gt;(_Sp_alloc_shared_tag&lt;_Alloc&gt;{__a},\r\n      |              ^\r\nsample.cpp:22:14: note: in instantiation of function template specialization 'std::make_shared&lt;Widget, WidgetOptions &amp;&gt;' requested here\r\n   22 |         std::make_shared&lt;Widget&gt;(options);\r\n      |              ^\r\nsample.cpp:11:5: note: candidate constructor not viable: no known conversion from 'WidgetOptions' to 'const WidgetOptions *' for 1st argument; take the address of the argument with &amp;\r\n   11 |     Widget(WidgetOptions const* options);\r\n      |     ^      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\nsample.cpp:9:8: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'WidgetOptions' to 'const Widget' for 1st argument\r\n    9 | struct Widget\r\n      |        ^~~~~~\r\nsample.cpp:9:8: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'WidgetOptions' to 'Widget' for 1st argument\r\n    9 | struct Widget\r\n      |        ^~~~~~\r\n1 error generated.\r\nCompiler returned: 1\r\n<\/pre>\n<p>And for msvc:<\/p>\n<pre style=\"white-space: pre-wrap;\">xutility(408): error C2665: 'Widget::Widget': no overloaded function could convert all the argument types\r\nsample.cpp(14): note: could be 'Widget::Widget(Widget &amp;&amp;)'\r\nxutility(408): note: 'Widget::Widget(Widget &amp;&amp;)': cannot convert argument 1 from 'WidgetOptions' to 'Widget &amp;&amp;'\r\nxutility(408): note: Reason: cannot convert from 'WidgetOptions' to 'Widget'\r\nxutility(408): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called\r\nsample.cpp(14): note: or       'Widget::Widget(const Widget &amp;)'\r\nxutility(408): note: 'Widget::Widget(const Widget &amp;)': cannot convert argument 1 from 'WidgetOptions' to 'const Widget &amp;'\r\nxutility(408): note: Reason: cannot convert from 'WidgetOptions' to 'const Widget'\r\nxutility(408): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called\r\nsample.cpp(11): note: or       'Widget::Widget(const WidgetOptions *)'\r\nxutility(408): note: 'Widget::Widget(const WidgetOptions *)': cannot convert argument 1 from 'WidgetOptions' to 'const WidgetOptions *'\r\nxutility(408): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called\r\nxutility(408): note: while trying to match the argument list '(WidgetOptions)'\r\nxutility(408): note: the template instantiation context (the oldest one first) is\r\nsample.cpp(22): note: see reference to function template instantiation 'std::shared_ptr&lt;Widget&gt; std::make_shared&lt;Widget,WidgetOptions&amp;&gt;(WidgetOptions &amp;)' being compiled\r\nmemory(2896): note: see reference to function template instantiation 'std::_Ref_count_obj2&lt;_Ty&gt;::_Ref_count_obj2&lt;WidgetOptions&amp;&gt;(WidgetOptions &amp;)' being compiled\r\n        with\r\n        [\r\n            _Ty=Widget\r\n        ]\r\nmemory(2083): note: see reference to function template instantiation 'void std::_Construct_in_place&lt;_Ty,WidgetOptions&amp;&gt;(_Ty &amp;,WidgetOptions &amp;) noexcept(false)' being compiled\r\n        with\r\n        [\r\n            _Ty=Widget\r\n        ]\r\nCompiler returned: 2\r\n<\/pre>\n<p>The trick to understanding C++ compiler error messages is to focus on two things. First, look at the beginning of the error message, which tells you what went wrong at a very low level. Then skip over the intermediate errors that follow the chain of calls until you end up at the line of code that <i>you<\/i> wrote. That original line of code is the one that is leading the compiler to a bad place. After that, you sometimes get supplemental information that helps you understand the low-level error better.<\/p>\n<p>For the gcc error, it starts with trying to call <code>void std::_Construct(_Tp*, _Args&amp;&amp; ...)<\/code>, and if you substitute the template parameters, it expands to <code>void std::_Construct(Widget*, WidgetOptions&amp;)<\/code>. From the function name, it sounds like it&#8217;s trying to construct something, and my guess is that it&#8217;s trying to construct the type <code>_Tp<\/code> (which is <code>Widget<\/code>) from the arguments (which are <code>WidgetOptions&amp;<\/code>). Then follows a chain of &#8220;required from&#8221;s that ultimately lead to <code>std::make_shared&lt;Widget&gt;(options)<\/code>, which is the line of code that we wrote that created the problem in the first place.<\/p>\n<p>After that comes a little more explanation: &#8220;No matching function for call to <code>Widget::<wbr \/>Widget(<wbr \/>Widget\u00adOptions&amp;)<\/code>.&#8221; So it&#8217;s trying to call the <code>Widget<\/code> constructor with a <code>Widget\u00adOptions&amp;<\/code> but can&#8217;t, and the rest of the error message is listing the various constructor candidates and why each one doesn&#8217;t work.<\/p>\n<p>For the clang error, it starts with the &#8220;No matching constructor&#8221; portion, though for some reason it doesn&#8217;t tell you what <code>_Tp<\/code> and <code>_Args<\/code> are. Then comes a chain of &#8220;in instantiation of&#8221; messages until it reaches <code>std::make_<wbr \/>shared&lt;Widget(options)<\/code>, which is the line of code we wrote.<\/p>\n<p>After the chain of instantiations, clang provides details on why it couldn&#8217;t find a matching constructor.<\/p>\n<p>Finally, we have msvc, which does things in a different order. It starts by telling you that it couldn&#8217;t construct a <code>Widget<\/code> from the provided arguments. Unfortunately, it doesn&#8217;t come right out and tell you what the arguments are, though from the third part of the message &#8220;cannot convert argument 1 from &#8216;<code>Widget\u00adOptions<\/code>&#8216; to &#8216;<code>Widget&amp;&amp;<\/code>&#8216;&#8221; you can infer that the first argument is a <code>Widget\u00adOptions<\/code>. After explaining why each constructor candidate was unsuitable, it gives you the function instantiation chain, starting with the <code>std::make_<wbr \/>shared&lt;Widget, Widget\u00adOptions&amp;&gt;(Widget\u00adOptions&amp;)<\/code>.<\/p>\n<p>So all of them are telling you that the <code>std::make_<wbr \/>shared&lt;Widget(options)<\/code> is the line of code that created the problem, and the reason is that it couldn&#8217;t find a suitable <code>Widget<\/code> constructor.<\/p>\n<p>Study the part of the message that explains why each candidate was unsuitable, and look at the part where the compiler rejects the constructor you thought you were using. In our case, we wanted to use the <code>Widget(WidgetOptions const* options)<\/code> constructor.<\/p>\n<pre style=\"white-space: pre-wrap;\">\/\/ clang\r\nno known conversion for argument 1 from 'WidgetOptions' to 'const WidgetOptions*'\r\n\r\n\/\/ gcc\r\nno known conversion from 'WidgetOptions' to 'const WidgetOptions *' for 1st argument; take the address of the argument with &amp;\r\n\r\n\/\/ msvc\r\ncannot convert argument 1 from 'WidgetOptions' to 'const WidgetOptions *'\r\n<\/pre>\n<p>The problem is that we passed a <code>Widget\u00adOptions<\/code> object, but the constructor wanted a <code>const Widget\u00adOptions*<\/code> pointer. We should have passed a pointer to the options rather than the options itself. The gcc compiler even guessed that that was what you intended.<\/p>\n<p>So that&#8217;s the trick: Read the start of the error message to find out what went wrong, and then skip over all the intermediate steps to find the line of code you wrote that caused the error. Use your understanding of what your code was trying to do to understand why the compiler couldn&#8217;t do it. In our case, we were trying to construct a shared <code>Widget<\/code>, and our attention was drawn to the inability to call the constructor correctly.<\/p>\n<p><b>Bonus chatter<\/b>: The library authors could do us a solid here and add a special diagnostic to identify the problem sooner. They could put something at the start of <code>make_shared<\/code> like this:<\/p>\n<pre>static_assert(std::is_constructible_v&lt;_Tp, _Args&amp;&amp;&gt;,\r\n    \"Cannot construct the object from the provided parameters. \"\r\n    \"See subsequent error messages for details.\");\r\n<\/pre>\n<p>This adds a message to the error spew that helps guide the developer to the part of the subsequent error message that they should focus on.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Understanding what you asked the compiler to do, and why it couldn&#8217;t comply.<\/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-110619","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Understanding what you asked the compiler to do, and why it couldn&#8217;t comply.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110619","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=110619"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110619\/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=110619"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=110619"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=110619"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}