Note that there are some explanatory texts on larger screens.

plurals
  1. POImplementing swap() for objects with internal pointers
    primarykey
    data
    text
    <p>I'm implementing the <a href="https://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom">copy-and-swap idiom</a> for <code>operator=</code> of a small non-owning-memory-referencing object I've designed. When <code>MemRef</code> is referencing a piece of a buffer whose lifetime I trust, <code>_ptr</code> points into the buffer, as you'd expect.</p> <p>What is unusual about this <code>MemRef</code> is that it consists not only of a <code>_ptr</code> and a <code>_len</code>, but also a <code>_memory</code> <code>std::string</code>: there are certain users (or situations) of this class whom I <em>do not</em> trust to protect their memory; for them, I actually copy their memory into the <code>_memory</code> string during construction, and set <code>_ptr = _memory.c_str()</code>. I can always determine whether I have an "inref" MemRef (referring to its internal memory) or an "exref" MemRef (referring to some external buffer) by asking if <code>_ptr == _memory.c_str()</code>.</p> <p>I'm confused about how to write the swap routine. The following is taken from <a href="https://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom">copy-and-swap idiom</a>:</p> <p>Here's <code>operator=</code>:</p> <pre><code>MemRef&amp; MemRef::operator=(MemRef other) { swap(*this, other); return *this; } </code></pre> <p>Here's the copy constructor:</p> <pre><code>// Copy ctor MemRef::MemRef(const MemRef&amp; other) : _memory(other._memory), _ptr(other._ptr), _len(other._len) { // Special provision if copying an "inref" MemRef if (other._ptr == other._memory.c_str()) { _ptr = _memory.c_str(); } } </code></pre> <p>And here's my <code>swap(first, second)</code> - which I believe needs more work.</p> <pre><code>void swap(MemRef&amp; first, MemRef&amp; second) { using std::swap; swap(first._memory, second._memory); swap(first._ptr, second._ptr); swap(first._len, second._len); } </code></pre> <p>So if I have:</p> <pre><code>MemRef mr_a("foo"); // creates an "inref" memref MemRef mr_b(buffer_ptr, length); // creates an "exref" memref -&gt; "blarch" mr_a = mr_b; </code></pre> <p><code>operator=()</code> gets called with a temporary MemRef built by copy-constructing mr_b; it calls <code>swap(mr_a, mr_b_copy);</code> <code>swap()</code> exchanges the pointer, length, and string (so that mr_a's former contents will be destructed along with mr_b_copy). </p> <p>What I don't understand is whether the pointers in mr_a and mr_b_copy are correct at this point, or if they're tangled up with each other.</p> <p><strong>UPDATE 1</strong>: The above example doesn't illustrate the problem. Consider this one:</p> <pre><code>MemRef mr_a; // creates a memref with _ptr(NULL), _len(0) mr_a = "woof"; // </code></pre> <p>For passing by value to operator=(), a temporary <strong>inref</strong> is constructed for "woof" and bound to the parameter <code>other</code>. Then, references to <code>mr_a</code> and to <code>other</code> are passed to swap() and bound as <code>first</code> and <code>second</code> respectively. After the swap, <code>first._ptr</code> was ... well, <em>wrong</em>. Pointing to garbage. Here's what I had to do:</p> <pre><code>void swap(MemRef&amp; first, MemRef&amp; second) { using std::swap; // second is an exref if (second._ptr != second._memory.c_str()) { swap(first._memory, second._memory); swap(first._len, second._len); swap(first._ptr, second._ptr); } // second is an inref else { swap(first._memory, second._memory); swap(first._len, second._len); first._ptr = first._memory.c_str(); } } </code></pre> <p>All I can conclude is that std::swap(string, string) is doing something strange.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    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