Я реализую идиому копирования и свопинга для operator= небольшого объекта, не связанного с владением памятью, который я разработал. Когда MemRef ссылается на кусок буфера, чье жизненное время я доверяю, _ptr указывает на буфер, как и следовало ожидать.
Что необычно в этом MemRef заключается в том, что он состоит не только из _ptr и a _len, но также и _memory std::string: есть определенные пользователи (или ситуации) этого класса, Я не верю, чтобы защитить их память; для них я фактически копирую свою память в строку _memory во время построения и устанавливаю _ptr = _memory.c_str(). Я всегда могу определить, есть ли у меня "inref" MemRef (ссылаясь на его внутреннюю память) или "exref" MemRef (ссылаясь на некоторый внешний буфер), спрашивая, есть ли _ptr == _memory.c_str().
Я смущен тем, как писать процедуру подкачки. Из идиомы копирования и свопинга взято следующее:
Здесь operator=:
MemRef&
MemRef::operator=(MemRef other) {
swap(*this, other);
return *this;
}
Здесь конструктор копирования:
// 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();
}
}
И вот мой swap(first, second) - который, мне кажется, требует больше работы.
void
swap(MemRef& first, MemRef& second) {
using std::swap;
swap(first._memory, second._memory);
swap(first._ptr, second._ptr);
swap(first._len, second._len);
}
Итак, если у меня есть:
MemRef mr_a("foo"); // creates an "inref" memref
MemRef mr_b(buffer_ptr, length); // creates an "exref" memref -> "blarch"
mr_a = mr_b;
operator=() вызывается с временным MemRef, созданным копированием mr_b; он вызывает swap(mr_a, mr_b_copy); swap() обменивает указатель, длину и строку (так что прежнее содержимое mr_a будет разрушено вместе с mr_b_copy).
Я не понимаю, являются ли указатели в mr_a и mr_b_copy правильными в этой точке, или если они запутались друг с другом.
ОБНОВЛЕНИЕ 1. Приведенный выше пример не иллюстрирует проблему. Рассмотрим это:
MemRef mr_a; // creates a memref with _ptr(NULL), _len(0)
mr_a = "woof"; //
Для передачи по значению оператору =() временный inref создается для "woof" и привязан к параметру other. Затем ссылки на mr_a и other передаются в swap() и связаны как first и second соответственно. После обмена, first._ptr был... ну, неправильно. Указывает на мусор. Вот что я должен был сделать:
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();
}
}
Я могу заключить, что std:: swap (string, string) делает что-то странное.