I'm implementing the copy-and-swap idiom for operator=
of a small non-owning-memory-referencing object I've designed. When MemRef
is referencing a piece of a buffer whose lifetime I trust, _ptr
points into the buffer, as you'd expect.
What is unusual about this MemRef
is that it consists not only of a _ptr
and a _len
, but also a _memory
std::string
: there are certain users (or situations) of this class whom I do not trust to protect their memory; for them, I actually copy their memory into the _memory
string during construction, and set _ptr = _memory.c_str()
. 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 _ptr == _memory.c_str()
.
I'm confused about how to write the swap routine. The following is taken from copy-and-swap idiom:
Here's operator=
:
MemRef&
MemRef::operator=(MemRef other) {
swap(*this, other);
return *this;
}
Here's the copy constructor:
// Copy ctor
MemRef::MemRef(const MemRef& 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();
}
}
And here's my swap(first, second)
- which I believe needs more work.
void
swap(MemRef& first, MemRef& second) {
using std::swap;
swap(first._memory, second._memory);
swap(first._ptr, second._ptr);
swap(first._len, second._len);
}
So if I have:
MemRef mr_a("foo"); // creates an "inref" memref
MemRef mr_b(buffer_ptr, length); // creates an "exref" memref -> "blarch"
mr_a = mr_b;
operator=()
gets called with a temporary MemRef built by copy-constructing mr_b; it calls swap(mr_a, mr_b_copy);
swap()
exchanges the pointer, length, and string (so that mr_a's former contents will be destructed along with mr_b_copy).
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.
UPDATE 1: The above example doesn't illustrate the problem. Consider this one:
MemRef mr_a; // creates a memref with _ptr(NULL), _len(0)
mr_a = "woof"; //
For passing by value to operator=(), a temporary inref is constructed for "woof" and bound to the parameter other
. Then, references to mr_a
and to other
are passed to swap() and bound as first
and second
respectively. After the swap, first._ptr
was ... well, wrong. Pointing to garbage. Here's what I had to do:
void
swap(MemRef& first, MemRef& 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();
}
}
All I can conclude is that std::swap(string, string) is doing something strange.