Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p><a href="http://en.cppreference.com/w/cpp/container/vector" rel="noreferrer"><code>std::vector</code></a> will manage the memory for you, like always, but this memory will be of pointers, not objects.</p> <p>What this means is that your classes will be lost in memory once your vector goes out of scope. For example:</p> <pre><code>#include &lt;vector&gt; struct base { virtual ~base() {} }; struct derived : base {}; typedef std::vector&lt;base*&gt; container; void foo() { container c; for (unsigned i = 0; i &lt; 100; ++i) c.push_back(new derived()); } // leaks here! frees the pointers, doesn't delete them (nor should it) int main() { foo(); } </code></pre> <p>What you'd need to do is make sure you delete all the objects before the vector goes out of scope:</p> <pre><code>#include &lt;algorithm&gt; #include &lt;vector&gt; struct base { virtual ~base() {} }; struct derived : base {}; typedef std::vector&lt;base*&gt; container; template &lt;typename T&gt; void delete_pointed_to(T* const ptr) { delete ptr; } void foo() { container c; for (unsigned i = 0; i &lt; 100; ++i) c.push_back(new derived()); // free memory std::for_each(c.begin(), c.end(), delete_pointed_to&lt;base&gt;); } int main() { foo(); } </code></pre> <p>This is difficult to maintain, though, because we have to remember to perform some action. More importantly, if an exception were to occur in-between the allocation of elements and the deallocation loop, the deallocation loop would never run and you're stuck with the memory leak anyway! This is called exception safety and it's a critical reason why deallocation needs to be done automatically.</p> <p>Better would be if the pointers deleted themselves. Theses are called smart pointers, and the standard library provides <a href="http://en.cppreference.com/w/cpp/memory/unique_ptr" rel="noreferrer"><code>std::unique_ptr</code></a> and <a href="http://en.cppreference.com/w/cpp/memory/shared_ptr" rel="noreferrer"><code>std::shared_ptr</code></a>.</p> <p><code>std::unique_ptr</code> represents a unique (unshared, single-owner) pointer to some resource. This should be your default smart pointer, and overall complete replacement of any raw pointer use.</p> <pre><code>auto myresource = /*std::*/make_unique&lt;derived&gt;(); // won't leak, frees itself </code></pre> <p><code>std::make_unique</code> is missing from the C++11 standard by oversight, but you can make one yourself. To directly create a <code>unique_ptr</code> (not recommended over <code>make_unique</code> if you can), do this:</p> <pre><code>std::unique_ptr&lt;derived&gt; myresource(new derived()); </code></pre> <p>Unique pointers have move semantics only; they cannot be copied:</p> <pre><code>auto x = myresource; // error, cannot copy auto y = std::move(myresource); // okay, now myresource is empty </code></pre> <p>And this is all we need to use it in a container:</p> <pre><code>#include &lt;memory&gt; #include &lt;vector&gt; struct base { virtual ~base() {} }; struct derived : base {}; typedef std::vector&lt;std::unique_ptr&lt;base&gt;&gt; container; void foo() { container c; for (unsigned i = 0; i &lt; 100; ++i) c.push_back(make_unique&lt;derived&gt;()); } // all automatically freed here int main() { foo(); } </code></pre> <p><code>shared_ptr</code> has reference-counting copy semantics; it allows multiple owners sharing the object. It tracks how many <code>shared_ptr</code>s exist for an object, and when the last one ceases to exist (that count goes to zero), it frees the pointer. Copying simply increases the reference count (and moving transfers ownership at a lower, almost free cost). You make them with <code>std::make_shared</code> (or directly as shown above, but because <code>shared_ptr</code> has to internally make allocations, it's generally more efficient and technically more exception-safe to use <code>make_shared</code>).</p> <pre><code>#include &lt;memory&gt; #include &lt;vector&gt; struct base { virtual ~base() {} }; struct derived : base {}; typedef std::vector&lt;std::shared_ptr&lt;base&gt;&gt; container; void foo() { container c; for (unsigned i = 0; i &lt; 100; ++i) c.push_back(std::make_shared&lt;derived&gt;()); } // all automatically freed here int main() { foo(); } </code></pre> <p>Remember, you generally want to use <code>std::unique_ptr</code> as a default because it's more lightweight. Additionally, <code>std::shared_ptr</code> can be constructed out of a <code>std::unique_ptr</code> (but not vice versa), so it's okay to start small.</p> <p>Alternatively, you could use a container created to store pointers to objects, such as a <a href="http://www.boost.org/libs/ptr_container/doc/ptr_container.html" rel="noreferrer"><code>boost::ptr_container</code></a>:</p> <pre><code>#include &lt;boost/ptr_container/ptr_vector.hpp&gt; struct base { virtual ~base() {} }; struct derived : base {}; // hold pointers, specially typedef boost::ptr_vector&lt;base&gt; container; void foo() { container c; for (int i = 0; i &lt; 100; ++i) c.push_back(new Derived()); } // all automatically freed here int main() { foo(); } </code></pre> <p>While <code>boost::ptr_vector&lt;T&gt;</code> had obvious use in C++03, I can't speak of the relevance now because we can use <code>std::vector&lt;std::unique_ptr&lt;T&gt;&gt;</code> with probably little to no comparable overhead, but this claim should be tested.</p> <p>Regardless, <em>never explicitly free things in your code</em>. Wrap things up to make sure resource management is dealt with automatically. You should have no raw owning pointers in your code.</p> <p>As a default in a game, I would probably go with <code>std::vector&lt;std::shared_ptr&lt;T&gt;&gt;</code>. We expect sharing anyway, it's fast enough until profiling says otherwise, it's safe, and it's easy to use.</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. 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