我正在为我设计的一个小型非拥有内存引用对象的operator=
实现copy-and-swap idiom。当MemRef
引用一段我信任的缓冲区时,_ptr
指向缓冲区,正如您所期望的那样。
这个MemRef
的不寻常之处在于,它不仅包含_ptr
和_len
,还包含_memory
std::string
:我不信任以保护他们记忆的这个类别的某些用户(或情境);对于他们,我实际上在构造期间将他们的记忆复制到_memory
字符串中,并设置_ptr = _memory.c_str()
。我总能确定我是否有" inref" MemRef(指其内部存储器)或" exref" MemRef(指一些外部缓冲区)询问_ptr == _memory.c_str()
。
我对如何编写交换例程感到困惑。以下摘自copy-and-swap idiom:
此处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;
使用由复制构造mr_b构建的临时MemRef调用 operator=()
;它调用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"; //
为了将值传递给operator =(),为" woof"构建了一个临时的 inref 。并绑定到参数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)正在做一些奇怪的事情。
答案 0 :(得分:1)
随着问题的更新,我想我可以看到问题是什么=)
在您的初始swap()
函数中,您有以下这些行:
swap(first._memory, second._memory);
swap(first._ptr, second._ptr);
swap(first._len, second._len);
如果这些都是exrefs,那么一切都很好 - 交换将按计划执行。但是,如果一个是inref(现在,我们将使用您提供的示例),那么这就是:
在这些方面:
MemRef mr_a; // creates a memref with _ptr(NULL), _len(0)
mr_a = "woof";
正如您所说,从“woof”创建了一个临时的 inref ,其_ptr
变量指向_memory.c_str()
的开头。
现在,当你的swap()
被调用时,首先会发生这种情况:
swap(first._memory, second._memory);
到目前为止一切都很好。你已经交换了字符串 - 但是他们的地址没有改变,只有他们的内容。从标准:
References, pointers, and iterators referring to the elements of a
basic_string sequence may be invalidated by the following uses of that
basic_string object: — As an argument to non-member functions swap()...
C++ International Standard n1905
现在,在行
期间swap(first._ptr, second._ptr);
你介绍了问题。那些指向未定义的地方 - 通过交换字符串,我们无效任何指针/迭代器/对字符串或其成员的引用,包括c_str() - 但我们绝对不要不要交换内存位置。因此,在这种情况下交换指针是错误的,正如您所意识到的那样。
幸运的是,您已经解决了这个问题 - 通过在inref的情况下重置指针而不是交换它们,您可以避免指向无效的内存位置,并且所有问题都已解决!希望这可以清除正在发生的事情=)
编辑:添加标准参考并澄清!