为具有内部指针的对象实现swap()
Implementing swap() for objects with internal pointers
我正在为我设计的一个小型非拥有内存引用对象的operator=
实现复制和交换习惯用法。当MemRef
引用我信任其生存期的缓冲区时,_ptr
会指向缓冲区,正如您所期望的那样。
这个MemRef
的不同寻常之处在于,它不仅由_ptr
和_len
组成,还由_memory
和std::string
组成:这个类的某些用户(或情况)我不信任他们来保护他们的内存;对于它们,我实际上在构建过程中将它们的内存复制到_memory
字符串中,并设置_ptr = _memory.c_str()
。我总是可以通过询问_ptr == _memory.c_str()
来确定我是否有"inref"MemRef(指其内部存储器)或"exref"MemRef(指某个外部缓冲区)。
我对如何编写交换例程感到困惑。以下内容取自复制和交换习惯用法:
这是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;
CCD_ 14通过复制构造mr_b构建的临时MemRef被调用;它调用swap(mr_a, mr_b_copy);
swap()
交换指针、长度和字符串(这样mr_a以前的内容将与mr_b_copy一起被销毁)。
我不明白的是,mr_a和mr_b_copy中的指针在这一点上是否正确,或者它们是否相互纠缠。
UPDATE 1:上面的例子没有说明这个问题。考虑一下这个:
MemRef mr_a; // creates a memref with _ptr(NULL), _len(0)
mr_a = "woof"; //
为了将值传递给运算符=(),为"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)正在做一些奇怪的事情。
随着问题的更新,我想我可以看到问题是什么了=)
在最初的swap()
函数中,您有以下行:
swap(first._memory, second._memory);
swap(first._ptr, second._ptr);
swap(first._len, second._len);
如果这些都是裁判,一切都很好——交换会按计划进行。然而,如果其中一个是inref(目前,我们将使用您提供的示例),那么这就是:
在这些行中:
MemRef mr_a; // creates a memref with _ptr(NULL), _len(0)
mr_a = "woof";
正如您所说的,临时inref是从"woof"创建的,其_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++国际标准n1905
所以现在,在生产线
swap(first._ptr, second._ptr);
你介绍普罗伦。它们指向某个未定义的位置-通过交换字符串,我们使字符串或其成员的任何指针/迭代器/引用无效,包括c_str()-但我们肯定不交换内存位置。因此,正如您所意识到的,在这种情况下交换指针是错误的。
幸运的是,您已经解决了这个问题——通过在inref的情况下重置指针而不是交换指针,您可以避免指向无效的内存位置,所有问题都得到了解决!希望这能澄清正在发生的事情=)
编辑:添加标准参考并澄清!
- 如果没有malloc,链表实现将失败
- 如何在c++中实现处理器调度模拟器
- 如何在c++中使用引用实现类似python的行为
- 实现无开销push_back的最佳方法是什么
- 使用简单类型列表实现的指数编译时间.为什么
- 如何在BST的这个简单递归实现中消除警告
- 实现一个在集合上迭代的模板函数
- 我应该实现右值推送功能吗?我应该使用std::move吗
- 如何正确实现和访问运算符的各种自定义枚举器
- C++Union/Struct位域的实现和可移植性
- 这个极客对极客的trie实现是否存在内存泄漏问题
- 为什么要将 swap() 实现为非抛出
- 使用静态tmp变量为简单类型C++重新实现std::swap()
- 为具有内部指针的对象实现swap()
- 为什么使用 swap 来实现复制分配
- std::vector::swap 是如何实现的
- 重新实现std::swap,我应该为tmp变量使用const吗
- 标准库如何实现std::swap
- 避免在RAM和SWAP内存之间切换的可选实现
- Swap() 函数的什么实现更好,适用于什么情况