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

时间:2013-12-11 06:02:21

标签: c++ swap

我正在为我设计的一个小型非拥有内存引用对象的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_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)正在做一些奇怪的事情。

1 个答案:

答案 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的情况下重置指针而不是交换它们,您可以避免指向无效的内存位置,并且所有问题都已解决!希望这可以清除正在发生的事情=)

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