为具有内部指针的对象实现swap()

Implementing swap() for objects with internal pointers

本文关键字:实现 swap 对象 内部 指针      更新时间:2023-10-16

我正在为我设计的一个小型非拥有内存引用对象的operator=实现复制和交换习惯用法。当MemRef引用我信任其生存期的缓冲区时,_ptr会指向缓冲区,正如您所期望的那样。

这个MemRef的不同寻常之处在于,它不仅由_ptr_len组成,还由_memorystd::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_aother的引用被传递到swap(),并分别绑定为firstsecond。互换后,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的情况下重置指针而不是交换指针,您可以避免指向无效的内存位置,所有问题都得到了解决!希望这能澄清正在发生的事情=)

编辑:添加标准参考并澄清!