<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: llzzz</title>
    <description>The latest articles on DEV Community by llzzz (@z6123).</description>
    <link>https://dev.to/z6123</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4200729%2Fd61b01c6-1025-4937-a0be-2a228fe3443b.png</url>
      <title>DEV Community: llzzz</title>
      <link>https://dev.to/z6123</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/z6123"/>
    <language>en</language>
    <item>
      <title>Deep dive into the C++ Passkey idiom</title>
      <dc:creator>llzzz</dc:creator>
      <pubDate>Sun, 25 Oct 2026 09:36:52 +0000</pubDate>
      <link>https://dev.to/z6123/deep-dive-into-the-c-passkey-idiom-f3d</link>
      <guid>https://dev.to/z6123/deep-dive-into-the-c-passkey-idiom-f3d</guid>
      <description>&lt;h3&gt;
  
  
  1. Motivation: The Problem with &lt;code&gt;friend&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;In C++, &lt;code&gt;friend&lt;/code&gt; is a double-edged sword. If you allow your friend to touch you inappropriately, that would be hurt. If class &lt;code&gt;A&lt;/code&gt; befriends another class &lt;code&gt;B&lt;/code&gt;, then everything in &lt;code&gt;A&lt;/code&gt; becomes visible to &lt;code&gt;B&lt;/code&gt;. &lt;code&gt;friend&lt;/code&gt; grants all-or-nothing access — which is rarely what you actually want. You usually want your friend to only able to touch a portion of you.&lt;/p&gt;

&lt;p&gt;Consider the following scenario. You have a &lt;code&gt;Widget&lt;/code&gt; class that must be created through a factory, because the constructor needs to perform some privileged setup (registering with a resource manager, validating invariants, logging, and so on). But the constructor itself has to be &lt;code&gt;public&lt;/code&gt; for &lt;code&gt;std::make_unique&lt;/code&gt; or for the factory to reach it. The moment it is &lt;code&gt;public&lt;/code&gt;, anyone can construct a &lt;code&gt;Widget&lt;/code&gt; — and that is a correctness bug waiting to happen.&lt;/p&gt;

&lt;p&gt;You might reach for &lt;code&gt;friend&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WidgetFactory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Widget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;friend&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WidgetFactory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// grants access to EVERYTHING&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x_&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x_&lt;/span&gt;&lt;span class="p"&gt;{};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WidgetFactory&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_unique&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WidgetFactory&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// ok&lt;/span&gt;
    &lt;span class="c1"&gt;// auto bad = std::make_unique&amp;lt;Widget&amp;gt;(42); // also ok! constructor is public, but you dont want this...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This "works," but it is a blunt instrument. &lt;code&gt;WidgetFactory&lt;/code&gt; now has access to every private member of &lt;code&gt;Widget&lt;/code&gt;, not just the constructor. As &lt;code&gt;Widget&lt;/code&gt; grows, so does the accidental attack surface. And if you later need to grant the same narrow access to a &lt;code&gt;Debugger&lt;/code&gt; class, you add another &lt;code&gt;friend&lt;/code&gt;, and the surface widens again.&lt;/p&gt;

&lt;p&gt;The question this idiom answers is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;How can I let a specific class touch only a specific portion of my class — and nothing else?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And then now let me introduce the PassKey Idiom.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. The Classic Solution: A Nested PassKey
&lt;/h3&gt;

&lt;p&gt;The core idea is to make a public function that requires an argument nobody else can construct. That argument is the &lt;em&gt;passkey&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Widget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PassKey&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;friend&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;PassKey&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// this constructor is private&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PassKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x_&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_unique&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PassKey&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x_&lt;/span&gt;&lt;span class="p"&gt;{};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// auto w1 = Widget{Widget::PassKey{}, 42}; // compile error! cannot access private constructor&lt;/span&gt;
    &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;w2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ok&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things are worth calling out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The constructor &lt;code&gt;PassKey() = default;&lt;/code&gt; is implicitly private (it is a member of a class whose default access is private), and &lt;code&gt;Widget&lt;/code&gt; is its only friend.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Widget&lt;/code&gt;'s constructor is &lt;code&gt;public&lt;/code&gt;, so it satisfies the syntactic requirements of &lt;code&gt;std::make_unique&lt;/code&gt;. But it is only &lt;em&gt;callable&lt;/em&gt; by code that can produce a &lt;code&gt;PassKey&lt;/code&gt; — which, in practice, means only &lt;code&gt;Widget&lt;/code&gt; itself (or whatever &lt;code&gt;Widget&lt;/code&gt; chooses to befriend).&lt;/li&gt;
&lt;li&gt;In &lt;code&gt;main&lt;/code&gt;, the direct construction fails to compile because &lt;code&gt;Widget::PassKey&lt;/code&gt; is private. The only way in is through &lt;code&gt;create&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a clean, zero-boilerplate solution &lt;strong&gt;for a single class&lt;/strong&gt;. But it does not scale. If you have &lt;code&gt;Widget&lt;/code&gt;, &lt;code&gt;Gadget&lt;/code&gt;, and &lt;code&gt;Sprocket&lt;/code&gt;, you must replicate this nested-class boilerplate in every one of them. Worse, the authorized "friend" is baked into the nested definition, so if you want &lt;code&gt;Widget&lt;/code&gt;'s constructor callable by both a &lt;code&gt;Factory&lt;/code&gt; and a &lt;code&gt;Debugger&lt;/code&gt;, you either befriend both inside &lt;code&gt;PassKey&lt;/code&gt; or duplicate the pattern. How to solve this? we can use a template!&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Scaling Up: The Templated PassKey
&lt;/h3&gt;

&lt;p&gt;The templated PassKey decouples the mechanism from the class it protects. You define it once, and any class can use it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Passkey&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;friend&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;             &lt;span class="c1"&gt;// only T can construct a Passkey&amp;lt;T&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;Passkey&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// private: no one else can create one&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the authorized class can create a passkey, and unauthorized code cannot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WidgetFactory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WidgetDebugger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Widget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="c1"&gt;// Public constructor, but only callable by whoever can make a Passkey&amp;lt;WidgetFactory&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Passkey&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;WidgetFactory&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x_&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="c1"&gt;// A separate, narrower door for the debugger&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Passkey&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;WidgetDebugger&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x_&lt;/span&gt;&lt;span class="p"&gt;{};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WidgetFactory&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_unique&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Passkey&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;WidgetFactory&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WidgetDebugger&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Passkey&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;WidgetDebugger&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WidgetFactory&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// ok&lt;/span&gt;
    &lt;span class="n"&gt;WidgetDebugger&lt;/span&gt;&lt;span class="p"&gt;{}.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;          &lt;span class="c1"&gt;// ok&lt;/span&gt;

    &lt;span class="c1"&gt;// auto bad = std::make_unique&amp;lt;Widget&amp;gt;(Passkey&amp;lt;WidgetFactory&amp;gt;{}, 1); // error&lt;/span&gt;
    &lt;span class="c1"&gt;// WidgetDebugger{}.inspect(...) can't call Widget's ctor; Factory can't call dump()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The design now has two key properties:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Per-function granularity.&lt;/strong&gt; &lt;code&gt;Widget&lt;/code&gt;'s constructor admits only &lt;code&gt;WidgetFactory&lt;/code&gt;. &lt;code&gt;Widget::dump&lt;/code&gt; admits only &lt;code&gt;WidgetDebugger&lt;/code&gt;. Neither can use the other's door. No &lt;code&gt;friend&lt;/code&gt; grants blanket access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reusable mechanism.&lt;/strong&gt; &lt;code&gt;Passkey&amp;lt;T&amp;gt;&lt;/code&gt; is written once and works for any number of classes. There is no nested-class boilerplate to copy.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A subtle but important point: &lt;code&gt;std::make_unique&lt;/code&gt; cannot construct the &lt;code&gt;Passkey&lt;/code&gt; for you. The authorized class must explicitly pass &lt;code&gt;Passkey&amp;lt;WidgetFactory&amp;gt;{}&lt;/code&gt; into the constructor call. That is by design — &lt;code&gt;make_unique&lt;/code&gt; is not the privileged party; the caller is.&lt;/p&gt;

&lt;h4&gt;
  
  
  Improvement you can made if you are using C++20
&lt;/h4&gt;

&lt;p&gt;C++20 does not fundamentally change the PassKey mechanism. There is no concept that replaces it, because concepts constrain types, whereas PassKey constrains &lt;em&gt;who can produce a token&lt;/em&gt;. The two compose nicely, though: if you are building a generic system where the set of authorized callers is itself parameterized, you can write&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;type_traits&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="c1"&gt;// Marker: only types deriving from this may be a Caller.&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;Privileged&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

&lt;span class="c1"&gt;// Passkey&amp;lt;T&amp;gt; only exists if T is privileged.&lt;/span&gt;
&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;requires&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;is_base_of_v&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Privileged&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Passkey&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;friend&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;Passkey&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Widget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Passkey&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Factory&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x_&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x_&lt;/span&gt;&lt;span class="p"&gt;{};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Factory opts in — so it can make a Passkey&amp;lt;Factory&amp;gt;.&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Factory&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Privileged&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Passkey&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Factory&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Sneaky does NOT opt in — so Passkey&amp;lt;Sneaky&amp;gt; won't compile.&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Sneaky&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="c1"&gt;// Widget w{Passkey&amp;lt;Sneaky&amp;gt;{}, 1};  // error: constraint not satisfied&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the whole idea. Widget's constructor is public, but the only way to call it is to hand it a &lt;code&gt;Passkey&amp;lt;Factory&amp;gt;&lt;/code&gt; — and only Factory can construct one, because Factory is the friend. The requires clause adds one extra guarantee: you can't even write &lt;code&gt;Passkey&amp;lt;X&amp;gt;&lt;/code&gt; unless &lt;code&gt;X&lt;/code&gt; derives from Privileged, so unauthorized types fail at the template level instead of at the friend level.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Group Permissions: Variadic Friends (C++26)
&lt;/h3&gt;

&lt;p&gt;The templated PassKey has one remaining friction point. Suppose a single function should be callable by &lt;em&gt;several&lt;/em&gt; authorized classes — say a &lt;code&gt;Factory&lt;/code&gt;, a &lt;code&gt;Debugger&lt;/code&gt;, and a &lt;code&gt;Serializer&lt;/code&gt;. Before C++26, you cannot write &lt;code&gt;friend Ts...&lt;/code&gt;; expanding a parameter pack in a friend declaration is ill-formed. The workarounds are ugly: manual overloads, a combined passkey type, or a chain of nested friends.&lt;/p&gt;

&lt;p&gt;C++26 fixes this with &lt;strong&gt;variadic friends&lt;/strong&gt; (P2893R3). You can now expand a pack directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="c1"&gt;// C++26: variadic friends — one passkey authorizes a whole pack of types.&lt;/span&gt;
&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="nc"&gt;Ts&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Passkey&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;friend&lt;/span&gt; &lt;span class="n"&gt;Ts&lt;/span&gt;&lt;span class="p"&gt;...;&lt;/span&gt;
    &lt;span class="n"&gt;Passkey&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Factory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Debugger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Serializer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Widget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="c1"&gt;// Only Factory, Debugger, and Serializer can call this.&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;secretInit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Passkey&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Factory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Debugger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Serializer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Widget initialized&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Each authorized type can build the passkey — and thus call secretInit.&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Factory&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;secretInit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Passkey&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Factory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Debugger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Serializer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{});&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Debugger&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;poke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;secretInit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Passkey&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Factory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Debugger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Serializer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{});&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Serializer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;secretInit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Passkey&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Factory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Debugger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Serializer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{});&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Not in the pack — cannot construct the passkey.&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Intruder&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="c1"&gt;// void tryIt(Widget&amp;amp; w) { w.secretInit(Passkey&amp;lt;Factory, Debugger, Serializer&amp;gt;{}); }&lt;/span&gt;
    &lt;span class="c1"&gt;//   ^ error: Passkey ctor is private; Intruder is not a friend.&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;Factory&lt;/span&gt;&lt;span class="p"&gt;{}.&lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;        &lt;span class="c1"&gt;// ok&lt;/span&gt;
    &lt;span class="n"&gt;Debugger&lt;/span&gt;&lt;span class="p"&gt;{}.&lt;/span&gt;&lt;span class="n"&gt;poke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;       &lt;span class="c1"&gt;// ok&lt;/span&gt;
    &lt;span class="n"&gt;Serializer&lt;/span&gt;&lt;span class="p"&gt;{}.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;     &lt;span class="c1"&gt;// ok&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes the "group permission" case a one-liner and removes the need for the combined-type hack. It is a small language feature, but for the PassKey idiom it is a meaningful ergonomic win: the passkey now expresses &lt;em&gt;"these N types, and no others"&lt;/em&gt; directly in the type system.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Performance and Trade-offs
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Runtime cost
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;In theory&lt;/strong&gt;, passing an empty object by value could cost a register or a stack slot. &lt;strong&gt;In practice&lt;/strong&gt;, in optimized builds, it is a &lt;strong&gt;zero-cost abstraction&lt;/strong&gt;. Because &lt;code&gt;Passkey&lt;/code&gt; has no data members and the parameter is unnamed, the optimizer elides it entirely at &lt;code&gt;-O1&lt;/code&gt; and above. There is no runtime check, no branch, no token comparison — the entire mechanism lives in the type system and disappears in the emitted code.&lt;/p&gt;

&lt;h4&gt;
  
  
  The one caveat
&lt;/h4&gt;

&lt;p&gt;If the protected function is not inlined (defined in a separate translation unit, and LTO is disabled), the calling convention may still require passing a byte for the empty class to satisfy the ABI. This is a minor, usually irrelevant cost. For header-only or inlined usage — which is the common case — there is no overhead at all.&lt;/p&gt;

&lt;h4&gt;
  
  
  Compile-time cost
&lt;/h4&gt;

&lt;p&gt;Slightly more template instantiation (one specialization per authorized type), and slightly longer function signatures. This is the real price, but it is  usually trivial.&lt;/p&gt;

&lt;h4&gt;
  
  
  Readability trade-offs
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Signatures get noisier: &lt;code&gt;Widget(Passkey&amp;lt;Factory&amp;gt;, int)&lt;/code&gt; is visually heavier than &lt;code&gt;Widget(int)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The unnamed parameter convention (see below) is what keeps it readable; without it, reviewers wonder what the argument is for.&lt;/li&gt;
&lt;li&gt;The mechanism is &lt;em&gt;compile-time enforced&lt;/em&gt;, so the compiler error when someone tries to bypass it is clear — but the &lt;em&gt;reason&lt;/em&gt; the parameter exists is not obvious to a reader seeing the class for the first time. A brief comment on the constructor is worth the cost.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  6. Idiomatic Usage and Best Practices
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Leave the parameter unnamed.&lt;/strong&gt; Write &lt;code&gt;void foo(Passkey&amp;lt;T&amp;gt;)&lt;/code&gt;, not &lt;code&gt;void foo(Passkey&amp;lt;T&amp;gt; key)&lt;/code&gt;. The unnamed parameter signals "this is a token, not data — it carries no information and is never used in the body."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mark the constructor &lt;code&gt;explicit&lt;/code&gt; if you are being defensive.&lt;/strong&gt; &lt;code&gt;explicit Passkey() = default;&lt;/code&gt; is not strictly required — the private access already blocks unauthorized construction — but it guards against brace-initialization surprises and makes intent explicit. It is harmless and recommended for older-standard compatibility (C++17 or earlier).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prefer the templated form.&lt;/strong&gt; The nested form is fine as a teaching example, but the templated form is the one to use in production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document the contract.&lt;/strong&gt; A one-line comment — &lt;code&gt;// only Factory may construct Widget&lt;/code&gt; — saves future readers from reverse-engineering the idiom.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  8. Summary
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;friend&lt;/code&gt; is all-or-nothing; the PassKey idiom gives you &lt;strong&gt;per-function, per-caller&lt;/strong&gt; access control.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;nested&lt;/strong&gt; PassKey is the minimal teaching form; the &lt;strong&gt;templated&lt;/strong&gt; &lt;code&gt;Passkey&amp;lt;T&amp;gt;&lt;/code&gt; is the idiomatic production form.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;C++26 variadic friends&lt;/strong&gt; (&lt;code&gt;friend Ts...&lt;/code&gt;) turns "group permissions" into a one-liner, removing the last piece of friction.&lt;/li&gt;
&lt;li&gt;It is a &lt;strong&gt;zero-cost abstraction&lt;/strong&gt; in optimized builds; the cost is compile-time and readability, not runtime.&lt;/li&gt;
&lt;li&gt;Use it for restricted constructors and sensitive methods; use &lt;strong&gt;Attorney-Client&lt;/strong&gt; when you need to expose members instead.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>code</category>
      <category>cpp</category>
      <category>programming</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Why prefer std::make_unique over new in std::unique_ptr?</title>
      <dc:creator>llzzz</dc:creator>
      <pubDate>Sat, 24 Oct 2026 03:20:58 +0000</pubDate>
      <link>https://dev.to/z6123/why-prefer-stdmakeunique-over-new-in-stduniqueptr-3h9d</link>
      <guid>https://dev.to/z6123/why-prefer-stdmakeunique-over-new-in-stduniqueptr-3h9d</guid>
      <description>&lt;p&gt;In modern C++, when you need a &lt;code&gt;std::unique_ptr&lt;/code&gt;, the idiomatic way to create it is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_unique&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyClass&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;rather than manually &lt;code&gt;new&lt;/code&gt;-ing the object inside the &lt;code&gt;unique_ptr&lt;/code&gt; constructor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyClass&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;()};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;std::make_unique&lt;/code&gt; was introduced in C++14 to fill a gap that &lt;code&gt;std::make_shared&lt;/code&gt; had already covered for shared ownership. It is a small function template, but it carries several important advantages. This article walks through every reason to prefer it, notes what changed in C++17 and C++20, and covers the cases where you still need the raw &lt;code&gt;new&lt;/code&gt; form.&lt;/p&gt;

&lt;p&gt;the implementation of &lt;code&gt;std::make_unique&lt;/code&gt; is roughly the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="nc"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;make_unique&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;noexcept&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;forward&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)...});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1. Exception Safety
&lt;/h3&gt;

&lt;p&gt;This is traditionally cited as the main reason for &lt;code&gt;make_unique&lt;/code&gt;. Before C++17, the order in which function arguments are evaluated was unspecified. If you constructed a &lt;code&gt;unique_ptr&lt;/code&gt; with &lt;code&gt;new&lt;/code&gt; as one argument among several, a leak could occur if another argument threw &lt;strong&gt;after&lt;/strong&gt; the &lt;code&gt;new&lt;/code&gt; expression completed but &lt;strong&gt;before&lt;/strong&gt; the &lt;code&gt;unique_ptr&lt;/code&gt; constructor took ownership of the raw pointer.&lt;/p&gt;

&lt;p&gt;Here is an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;U&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;runtime_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"boom"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;{}},&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="p"&gt;{}});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before C++17, a compiler was permitted to evaluate &lt;code&gt;new T{}&lt;/code&gt; first, then evaluate &lt;code&gt;new U{}&lt;/code&gt;, and only then call the &lt;code&gt;unique_ptr&lt;/code&gt; constructors. If &lt;code&gt;new U{}&lt;/code&gt; threw, the memory allocated for &lt;code&gt;T&lt;/code&gt; had not yet been handed to a &lt;code&gt;unique_ptr&lt;/code&gt;, so it leaked.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;std::make_unique&lt;/code&gt; closes this hole because the allocation and the ownership transfer happen inside a single function call. The temporary &lt;code&gt;unique_ptr&lt;/code&gt; is fully constructed before the surrounding expression continues, so if a later argument throws, stack unwinding destroys the already-constructed &lt;code&gt;unique_ptr&lt;/code&gt; and frees the memory.&lt;/p&gt;

&lt;h4&gt;
  
  
  What changed in C++17
&lt;/h4&gt;

&lt;p&gt;C++17 tightened the evaluation-order rules. In a function call, each argument expression is now fully evaluated before the next argument is evaluated, although the order in which the arguments are evaluated relative to each other is still unspecified. Because of this, the manual &lt;code&gt;new&lt;/code&gt; form is no longer leak-prone in the exact multi-argument scenario above: once &lt;code&gt;new T{}&lt;/code&gt; completes and its &lt;code&gt;unique_ptr&lt;/code&gt; temporary is constructed, that temporary is a fully formed object, and an exception from another argument will destroy it correctly.&lt;/p&gt;

&lt;p&gt;So if you are compiling as C++17 or later, the exception-safety motivation for &lt;code&gt;make_unique&lt;/code&gt; is largely historical. The remaining reasons below are still valid.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Reduced Redundancy and &lt;code&gt;auto&lt;/code&gt; Type Deduction
&lt;/h3&gt;

&lt;p&gt;Using &lt;code&gt;make_unique&lt;/code&gt; lets you write the type name once and rely on &lt;code&gt;auto&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyClass&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// MyClass written twice&lt;/span&gt;
&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_unique&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyClass&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// written once&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Beyond brevity, this eliminates a class of bugs where the two type names drift apart during refactoring: one is changed but the other is not, producing a mismatched or ill-formed expression. The C++ Core Guidelines encode this as &lt;strong&gt;R.23: Use &lt;code&gt;make_unique()&lt;/code&gt; to make &lt;code&gt;unique_ptr&lt;/code&gt;s&lt;/strong&gt;, citing both conciseness and exception safety.&lt;/p&gt;

&lt;h4&gt;
  
  
  Polymorphism caveat
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;make_unique&lt;/code&gt; does not perform polymorphic type erasure automatically. With &lt;code&gt;auto&lt;/code&gt;, you get exactly the &lt;code&gt;unique_ptr&amp;lt;T&amp;gt;&lt;/code&gt; corresponding to the template argument:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;Base&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;virtual&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;Derived&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Base&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;p1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_unique&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;    &lt;span class="c1"&gt;// std::unique_ptr&amp;lt;Base&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;p2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_unique&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Derived&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// std::unique_ptr&amp;lt;Derived&amp;gt;, not unique_ptr&amp;lt;Base&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want a base-class handle, you must state the target type explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_unique&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Derived&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works because &lt;code&gt;unique_ptr&amp;lt;Derived&amp;gt;&lt;/code&gt; converts to &lt;code&gt;unique_ptr&amp;lt;Base&amp;gt;&lt;/code&gt; when &lt;code&gt;Derived*&lt;/code&gt; converts to &lt;code&gt;Base*&lt;/code&gt;. Also note the virtual destructor on &lt;code&gt;Base&lt;/code&gt;: without it, deleting a &lt;code&gt;Derived&lt;/code&gt; through a &lt;code&gt;Base*&lt;/code&gt; is undefined behavior.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Enforcing a "No Raw &lt;code&gt;new&lt;/code&gt;" Discipline
&lt;/h3&gt;

&lt;p&gt;Every occurrence of &lt;code&gt;new&lt;/code&gt; in application code must be audited for lifetime correctness: is it deleted exactly once, through the correct type, with the correct &lt;code&gt;delete&lt;/code&gt; form? &lt;code&gt;make_unique&lt;/code&gt; removes that audit burden from the call site. If the owning object has a correct lifetime, the &lt;code&gt;unique_ptr&lt;/code&gt; it produces has a correct lifetime.&lt;/p&gt;

&lt;p&gt;This lets you adopt a simple, mechanically checkable rule: &lt;strong&gt;do not write &lt;code&gt;new&lt;/code&gt; in your codebase except inside the implementation of a factory or a low-level container&lt;/strong&gt;. As Scott Meyers and others have put it, &lt;code&gt;make_unique&lt;/code&gt; teaches “never say &lt;code&gt;new&lt;/code&gt;/&lt;code&gt;delete&lt;/code&gt;” without disclaimers.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Array Safety
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;make_unique&lt;/code&gt; distinguishes scalar and array types and returns the appropriate &lt;code&gt;unique_ptr&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_unique&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// std::unique_ptr&amp;lt;int[]&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_unique&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// std::unique_ptr&amp;lt;int&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the manual constructor, nothing prevents you from writing a mismatched pair such as &lt;code&gt;std::unique_ptr&amp;lt;int&amp;gt;(new int[10])&lt;/code&gt; or &lt;code&gt;std::unique_ptr&amp;lt;int[]&amp;gt;(new int(42))&lt;/code&gt;, both of which lead to undefined behavior when the default deleter uses the wrong &lt;code&gt;delete&lt;/code&gt; form.&lt;/p&gt;

&lt;p&gt;(&lt;code&gt;make_unique&amp;lt;T[N]&amp;gt;&lt;/code&gt; for a fixed bound &lt;code&gt;N&lt;/code&gt; is also permitted, but it is almost always a mistake because &lt;code&gt;unique_ptr&amp;lt;T[N]&amp;gt;&lt;/code&gt; does not have array-covariant behavior in the way you might expect.)&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Consistency with &lt;code&gt;make_shared&lt;/code&gt; and Easy Switching
&lt;/h3&gt;

&lt;p&gt;You should already be using &lt;code&gt;std::make_shared&lt;/code&gt; for shared ownership (it performs a single combined allocation, unlike &lt;code&gt;shared_ptr&amp;lt;T&amp;gt;(new T)&lt;/code&gt;). Using &lt;code&gt;make_unique&lt;/code&gt; gives your codebase a uniform creation syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_unique&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_shared&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This consistency pays off when requirements change. Switching between exclusive and shared ownership becomes a one-token edit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_unique&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// change to std::make_shared&amp;lt;T&amp;gt;(args)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the manual form, that switch requires rewriting the declaration, removing &lt;code&gt;new&lt;/code&gt;, and reconciling the deleter.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. &lt;code&gt;std::make_unique_for_overwrite&lt;/code&gt; (C++20)
&lt;/h3&gt;

&lt;p&gt;C++20 added &lt;code&gt;std::make_unique_for_overwrite&lt;/code&gt; for the case where you want to allocate an object &lt;strong&gt;without value-initializing it&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_unique_for_overwrite&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_unique_for_overwrite&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyPod&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For scalar types, &lt;code&gt;make_unique&amp;lt;T&amp;gt;()&lt;/code&gt; value-initializes (&lt;code&gt;T()&lt;/code&gt;), which zero-initializes fundamental types. For large buffers this can be an unnecessary cost. &lt;code&gt;make_unique_for_overwrite&lt;/code&gt; performs default-initialization instead, matching what &lt;code&gt;new T&lt;/code&gt; does for fundamental types, while preserving all the ownership and exception-safety benefits of the factory function.&lt;/p&gt;

&lt;h3&gt;
  
  
  When &lt;em&gt;Not&lt;/em&gt; to Use &lt;code&gt;std::make_unique&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;There are two well-defined cases where the manual constructor is still required.&lt;/p&gt;

&lt;h4&gt;
  
  
  Custom deleters
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;make_unique&lt;/code&gt; always uses &lt;code&gt;std::default_delete&amp;lt;T&amp;gt;&lt;/code&gt;, which calls &lt;code&gt;delete&lt;/code&gt; (or &lt;code&gt;delete[]&lt;/code&gt;). It cannot accept a custom deleter, because its variadic template parameters are forwarded to the &lt;strong&gt;object constructor&lt;/strong&gt;, not to the &lt;code&gt;unique_ptr&lt;/code&gt; constructor. If you are wrapping a C API handle or a resource that is not released with &lt;code&gt;delete&lt;/code&gt;, construct the &lt;code&gt;unique_ptr&lt;/code&gt; directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;FILE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;decltype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;fclose&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"data.bin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"rb"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;fclose&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A common workaround is to define your own &lt;code&gt;make_unique&lt;/code&gt; overload for the resource type in your own namespace.&lt;/p&gt;

&lt;h4&gt;
  
  
  Private or protected constructors
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;std::make_unique&lt;/code&gt; is not a friend of your class, so it cannot invoke a private or protected constructor. If a class restricts construction to factory member functions, the factory must construct the raw pointer internally and pass it to a &lt;code&gt;unique_ptr&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Widget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;private:&lt;/span&gt;
    &lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or you can use the PassKey idiom if you really want to use &lt;code&gt;std::make_unique&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Widget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Key&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;private:&lt;/span&gt;
        &lt;span class="c1"&gt;// this constructor is private&lt;/span&gt;
        &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;friend&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// only this class can make a Key&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="c1"&gt;// "Public" constructor, but requires a Key you can't forge.&lt;/span&gt;
    &lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;size_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;size_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// error: Key's constructor is private&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;but the passkey idiom is a topic for a separate post, so we won't expand on it here.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;Default to &lt;code&gt;std::make_unique&lt;/code&gt;. Its headline selling point — exception safety — has lost some of its bite since C++17 tightened the evaluation-order rules, so consider the famous leak example a historical artifact rather than a live threat. The other arguments, though, are still pulling their weight: it writes the type once instead of twice, it plays nicely with &lt;code&gt;auto&lt;/code&gt;, it keeps your arrays and scalars from getting their &lt;code&gt;delete&lt;/code&gt;s crossed, and it lets you adopt a clean "no raw &lt;code&gt;new&lt;/code&gt;" policy without asterisks.&lt;/p&gt;

&lt;p&gt;Reach for the manual &lt;code&gt;unique_ptr&lt;/code&gt; constructor only when &lt;code&gt;make_unique&lt;/code&gt; genuinely can't help you: custom deleters (it always uses &lt;code&gt;default_delete&lt;/code&gt;) and constructors that are private or protected. Everywhere else, let &lt;code&gt;make_unique&lt;/code&gt; do the &lt;code&gt;new&lt;/code&gt;-ing so you don't have to.&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>programming</category>
      <category>system</category>
    </item>
  </channel>
</rss>
