{"id":106879,"date":"2022-07-21T07:00:00","date_gmt":"2022-07-21T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=106879"},"modified":"2022-07-21T07:50:10","modified_gmt":"2022-07-21T14:50:10","slug":"20220721-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220721-00\/?p=106879","title":{"rendered":"Making sure that people use <CODE>make_unique<\/CODE> and <CODE>make_shared<\/CODE> to make your object"},"content":{"rendered":"<p>Normally, the way you prevent people from constructor your object in an objectionable way is by making the constructor private and offering a factory method. That way, the only way to create the object is through the factory.<\/p>\n<pre>class Widget\r\n{\r\npublic:\r\n    template&lt;typename...Args&gt;\r\n    static auto Create(Args&amp;&amp;... args)\r\n    { return Widget(std::forward&lt;Args&gt;(args)...); }\r\n\r\nprivate:\r\n    Widget();\r\n    Widget(int);\r\n    Widget(int, int);\r\n\r\n    \/\/ Deny copy construction\r\n    Widget(Widget const&amp;) = delete;\r\n};\r\n<\/pre>\n<p>However, this trick doesn&#8217;t work with <code>make_<wbr \/>unique<\/code> <code>make_<wbr \/>shared<\/code> because they require that the construct be public, so that they can create the object that is being managed.<\/p>\n<p>For <code>make_<wbr \/>unique<\/code>, you can work around it by <code>new<\/code>&#8216;ing the object yourself and putting it directly into a <code>unique_<wbr \/>ptr<\/code>:<\/p>\n<pre>class Widget\r\n{\r\npublic:\r\n    template&lt;typename...Args&gt;\r\n    static auto Create(Args&amp;&amp;... args)\r\n    { return std::unique_ptr&lt;Widget&gt;\r\n        (std::forward&lt;Args&gt;(args)...); }\r\nprivate:\r\n    Widget();\r\n    Widget(int);\r\n    Widget(int, int);\r\n\r\n    \/\/ Deny copy construction\r\n    Widget(Widget const&amp;) = delete;\r\n};\r\n<\/pre>\n<p>You can also do this to bypass <code>make_<wbr \/>shared<\/code>, but it&#8217;s not quite the same because you lose the special optimization in <code>make_<wbr \/>shared<\/code> that allocates the object and its control block inside the same memory allocation.<\/p>\n<p>Since we generally like the &#8220;combined allocation&#8221; optimization, we are forced to make the constructor public. To avoid unwanted use of the constructor, we can make it impossible to invoke, using a trick we learned some time ago: <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210719-00\/?p=105454\"> Require an additional parameter of an inaccessible marker type<\/a>.<\/p>\n<pre>class Widget : <!-- backref: My class derives from std::enable_shared_from_this, but shared_from_this() doesn't work -->public std::enable_shared_from_this&lt;Widget&gt;\r\n{\r\nprivate:\r\n    struct secret { explicit secret() = default; };\r\npublic:\r\n    template&lt;typename...Args&gt;\r\n    static auto Create(Args&amp;&amp;... args)\r\n    { return std::make_shared&lt;Widget&gt;\r\n        (secret{}, std::forward&lt;Args&gt;(args)...); }\r\n\r\n    \/\/ public but unusable from outside the class\r\n    Widget(secret);\r\n    Widget(secret, int);\r\n    Widget(secret, int, int);\r\n\r\n    \/\/ Deny copy construction\r\n    Widget(Widget const&amp;) = delete;\r\n};\r\n<\/pre>\n<p>The public constructors take an instance of a private type called <code>secret<\/code>. The constructor of this private type is explicit so users can&#8217;t use the <code>{}<\/code> trick to construct the object without naming it.<\/p>\n<p>We can capture this pattern in a helper class:<\/p>\n<pre>template&lt;typename T&gt;\r\nstruct require_make_shared :\r\n    public std::enable_shared_from_this&lt;T&gt;\r\n{\r\nprotected:\r\n    struct use_the_create_method {\r\n        explicit use_the_create_method() = default;\r\n    };\r\n\r\npublic:\r\n    template&lt;typename...Args&gt;\r\n    static auto create(Args&amp;&amp;... args)\r\n    {\r\n        return std::make_shared&lt;T&gt;\r\n            (use_the_create_method{},\r\n             std::forward&lt;Args&gt;(args)...);\r\n    }\r\n\r\n    \/\/ Deny copy construction\r\n    require_make_shared(require_make_shared const&amp;) = delete;\r\n};\r\n\r\nclass Widget : public require_make_shared&lt;Widget&gt;\r\n{\r\npublic:\r\n    Widget(use_the_create_method);\r\n    Widget(use_the_create_method, int);\r\n    Widget(use_the_create_method, int, int);\r\n};\r\n\r\nvoid test()\r\n{\r\n    auto v1 = Widget::create(); \/\/ okay\r\n    auto v2 = std::make_shared&lt;Widget&gt;(); \/\/ nope\r\n    auto v3 = std::make_unique&lt;Widget&gt;(); \/\/ nope\r\n    Widget v4; \/\/ nope\r\n}\r\n<\/pre>\n<p>We name the marker type <code>use_<wbr \/>the_<wbr \/>create_<wbr \/>method<\/code> as another example of compiler error message metaprogramming: If somebody tries to create one of these things directly, they get an error message that includes the phrase &#8220;<code>use_<wbr \/>the_<wbr \/>create_<wbr \/>method<\/code>&#8220;, and that might clue them in that they need to use the <code>create()<\/code> method.<\/p>\n<p>Notice that if you forget to derive publicly from <code>require_<wbr \/>make_<wbr \/>shared<\/code>, then you can&#8217;t even <code>create<\/code> one!<\/p>\n<pre>class Widget : \/* private *\/ require_make_shared&lt;Widget&gt;\r\n{\r\npublic:\r\n    Widget(use_the_create_method);\r\n    Widget(use_the_create_method, int);\r\n    Widget(use_the_create_method, int, int);\r\n};\r\n\r\nvoid test()\r\n{\r\n    auto v1 = Widget::create(); \/\/ nope\r\n}\r\n<\/pre>\n<p>This is probably good enough to protect against simple mistakes. To protect against fancier mistakes, you could add a static assertion:<\/p>\n<pre>template&lt;typename T&gt;\r\nstruct require_make_shared :\r\n    public std::enable_shared_from_this&lt;T&gt;\r\n{\r\nprotected:\r\n    struct use_the_create_method {\r\n        explicit use_the_create_method() = default;\r\n    };\r\n\r\npublic:\r\n    template&lt;typename...Args&gt;\r\n    static auto create(Args&amp;&amp;... args)\r\n    {\r\n        <span style=\"color: blue;\">static_assert(std::is_convertible_v&lt;\r\n            T*, require_make_shared*&gt;,\r\n            \"Must derive publicly from require_make_shared\");<\/span>\r\n        return std::make_shared&lt;T&gt;\r\n            (use_the_create_method{},\r\n             std::forward&lt;Args&gt;(args)...);\r\n    }\r\n\r\n    \/\/ Deny copy construction\r\n    require_make_shared(require_make_shared const&amp;) = delete;\r\n};\r\n\r\nclass Widget : \/* private *\/ require_make_shared&lt;Widget&gt;\r\n{\r\npublic:\r\n    <span style=\"color: blue;\">auto create()\r\n    { return require_make_shared::create(); } \/\/ assertion failure<\/span>\r\n    Widget(use_the_create_method);\r\n    Widget(use_the_create_method, int);\r\n    Widget(use_the_create_method, int, int);\r\n};\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Using a secret signal in what is required to be a public constructor.<\/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-106879","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Using a secret signal in what is required to be a public constructor.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106879","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=106879"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106879\/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=106879"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=106879"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=106879"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}