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

C++ 为具有内部指针的对象实现swap(),c++,swap,C++,Swap,我正在实现我设计的一个小型非自有内存引用对象的for操作符=。当MemRef引用我信任其生存期的缓冲区片段时,\u ptr会像您所期望的那样指向缓冲区 这个MemRef的不寻常之处在于,它不仅由\u ptr和\u len组成,还包括\u内存std::string:我不信任此类的某些用户(或情况)来保护他们的内存;对于它们,我实际上在构造过程中将它们的内存复制到\u memory字符串中,并设置\u ptr=\u memory.c\u str()。我总是可以通过询问\u ptr==\u memor

我正在实现我设计的一个小型非自有内存引用对象的for
操作符=
。当
MemRef
引用我信任其生存期的缓冲区片段时,
\u ptr
会像您所期望的那样指向缓冲区

这个
MemRef
的不寻常之处在于,它不仅由
\u ptr
\u len
组成,还包括
\u内存
std::string
:我不信任此类的某些用户(或情况)来保护他们的内存;对于它们,我实际上在构造过程中将它们的内存复制到
\u memory
字符串中,并设置
\u ptr=\u memory.c\u str()
。我总是可以通过询问
\u ptr==\u memory.c\u str()
来确定我是有一个“inref”MemRef(指它的内部内存)还是一个“exref”MemRef(指一些外部缓冲区)

我对如何编写交换例程感到困惑。以下资料摘自:

下面是
操作符=

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();
    }
}
这是我的
交换(第一,第二)
——我认为这需要更多的工作

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=()
通过复制构造mr_b生成的临时MemRef调用;它调用
交换(mr_a,mr_b_copy)
swap()
交换指针、长度和字符串(这样,mr_a以前的内容将与mr_b_copy一起销毁)

我不明白的是,在这一点上,a先生和b先生副本中的指针是否正确,或者它们是否相互纠结

更新1:上述示例没有说明问题。考虑这一点:

MemRef mr_a;  // creates a memref with _ptr(NULL), _len(0)
mr_a = "woof"; // 
为了通过值传递给操作符=(),为“woof”构造了一个临时的inref,并绑定到参数
other
。然后,对
mr_a
other
的引用被传递到swap(),并分别绑定为
first
second
。交换后,
首先。_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);
MemRef mr_a;  // creates a memref with _ptr(NULL), _len(0)
mr_a = "woof";
如果这些都是EXREF,那么一切都很好——交换将按计划执行。但是,如果其中一个是inref(现在,我们将使用您提供的示例),则会发生以下情况:

在这些方面:

swap(first._memory, second._memory);
swap(first._ptr, second._ptr);
swap(first._len, second._len);
MemRef mr_a;  // creates a memref with _ptr(NULL), _len(0)
mr_a = "woof";
正如您所说的,一个临时的inref是从“woof”创建的,其
\u ptr
变量指向
\u memory.c\u str()
的开头

现在,当调用您的
swap()
时,首先会发生以下情况:

swap(first._memory, second._memory);
到目前为止一切都很好。您已经交换了字符串-但是它们的地址没有改变,只有内容没有改变。根据标准:

引用、指针和迭代器引用
基本_字符串序列可能因以下使用而无效:
基本字符串对象:-作为非成员函数swap()的参数…

那么现在,在排队的时候

swap(first._ptr, second._ptr);
你介绍问题。那些指向未定义的地方-通过交换字符串,我们使字符串或其成员的任何指针/迭代器/引用无效,包括c_str()-但是我们肯定不会交换nemory位置。因此,在这种情况下,交换指针是错误的,正如您所意识到的

幸运的是,您已经解决了这个问题-通过在inref情况下重置指针而不是交换指针,您可以避免指向无效的内存位置,所有问题都得到了解决!希望这能澄清发生的一切=)


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

@Mat:我相信是的,因为RHS是通过值传递给操作符=()。据我推测,这是“复制和交换成语”的诀窍之一。请看链接。我真的不知道为什么他们不会——如果我没有看错的话,你似乎对copyswap习语有相当的了解
mr_a
将inref更改为exref,我不确定这是否是您的意图-您到底觉得自己做错了什么?@CommanderCorianderSalamander:我添加了更新1以说明我实际遇到问题的地方。出于某种原因,当
second
是inref时,三个组件的简单交换似乎会首先离开。相同的地址,但现在有垃圾。就好像交换字符串不仅仅是移动“手柄”一样。干得好!我认为,如果我是彻底的,我应该将同样的逻辑应用于
第二个
;但是,由于
交换
仅由
运算符=
使用,并且当
运算符=
退出时,
第二个
将被销毁,因此严格来说这不是必需的。无论如何,现在我明白了为什么我的解决方案有效了,我对它更有信心了:-)