Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Deciding what smart pointer to use is a question of <em>ownership</em>. When it comes to resource management, object A <em>owns</em> object B if it is in control of the lifetime of object B. For example, member variables are owned by their respective objects because the lifetime of member variables is tied to the lifetime of the object. You choose smart pointers based on how the object is owned.</p> <p>Note that ownership in a software system is separate from ownership as we would think of it outside of software. For example, a person might "own" their home, but that doesn't necessarily mean that a <code>Person</code> object has control over the lifetime of a <code>House</code> object. Conflating these real world concepts with software concepts is a sure-fire way to program yourself into a hole.</p> <hr> <p>If you have sole ownership of the object, use <code>std::unique_ptr&lt;T&gt;</code>. </p> <p>If you have shared ownership of the object...<br> - If there are no cycles in ownership, use <code>std::shared_ptr&lt;T&gt;</code>.<br> - If there are cycles, define a "direction" and use <code>std::shared_ptr&lt;T&gt;</code> in one direction and <code>std::weak_ptr&lt;T&gt;</code> in the other.</p> <p>If the object owns you, but there is potential of having no owner, use normal pointers <code>T*</code> (e.g. parent pointers).</p> <p>If the object owns you (or otherwise has guaranteed existence), use references <code>T&amp;</code>.</p> <hr> <p>Caveat: Be aware of the costs of smart pointers. In memory or performance limited environments, it could be beneficial to just use normal pointers with a more manual scheme for managing memory.</p> <p>The costs:</p> <ul> <li>If you have a custom deleter (e.g. you use allocation pools) then this will incur overhead per pointer that may be easily avoided by manual deletion.</li> <li><code>std::shared_ptr</code> has the overhead of a reference count increment on copy, plus a decrement on destruction followed by a 0-count check with deletion of the held object. Depending on the implementation, this can bloat your code and cause performance issues.</li> <li>Compile time. As with all templates, smart pointers contribute negatively to compile times.</li> </ul> <hr> <p>Examples:</p> <pre><code>struct BinaryTree { Tree* m_parent; std::unique_ptr&lt;BinaryTree&gt; m_children[2]; // or use std::array... }; </code></pre> <p>A binary tree does not own its parent, but the existence of a tree implies the existence of its parent (or <code>nullptr</code> for root), so that uses a normal pointer. A binary tree (with value semantics) has sole ownership of its children, so those are <code>std::unique_ptr</code>.</p> <pre><code>struct ListNode { std::shared_ptr&lt;ListNode&gt; m_next; std::weak_ptr&lt;ListNode&gt; m_prev; }; </code></pre> <p>Here, the list node owns its next and previous lists, so we define a direction and use <code>shared_ptr</code> for next and <code>weak_ptr</code> for prev to break the cycle.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload