对内部指针的对象实现swap() [英] Implementing swap() for objects with internal pointers

查看:192
本文介绍了对内部指针的对象实现swap()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在实施复制和交换惯用语对于我设计的一个小的非占有内存引用对象的 operator = 。当 MemRef 引用一个缓冲区,它的生命周期我信任, _ptr 指向缓冲区,



这个 MemRef 的不寻常之处在于它不仅包含一个 _ptr _len ,还有 _memory std: :string :这个类的某些用户(或情境)我不会信任来保护他们的记忆;对于他们,我实际上在构建期间将它们的内存复制到 _memory 字符串中,并设置 _ptr = _memory.c_str() 。我总是可以通过询问 _ptr == _memory.c_str()是否有一个inrefMemRef(指它的内部存储器)或exrefMemRef(指一些外部缓冲区) / code>。



我很困惑如何编写交换程序。以下摘自复制和交换惯用语



以下是 operator =

  MemRef& 
MemRef :: operator =(MemRef other){
swap(* this,other);
return * this;
}

这里是复制构造函数:

  //复制ctor 
MemRef :: MemRef(const MemRef& other):
_memory(other._memory),
_ptr如果复制一个inref,则特殊规定MemRef
if(other._ptr == other._memory.c_str()){
_ptr = _memory.c_str();
}
}

这里是我的 swap第一,第二) - 我相信需要更多的工作。

  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); //创建一个inrefmemref 
MemRef mr_b(buffer_ptr,length); //创建一个exrefmemref - > blarch
mr_a = mr_b;

通过复制构造mr_b构建的临时MemRef;它调用 swap(mr_a,mr_b_copy); swap()交换指针,长度和字符串以前的内容将与mr_b_copy一起被破坏)。



我不明白是mr_a和mr_b_copy中的指针在这一点上是否正确,或者它们是否相互纠结。



UPDATE 1 :上述示例未说明问题。考虑这个:

  MemRef mr_a; // create an memref with _ptr(NULL),_len(0)
mr_a =woof; //

对于将值传递给operator =(),临时 inref 为woof构造并绑定到参数 other 。然后,对 mr_a 其他的引用传递给swap(),并绑定为 。在交换后, first._ptr 是...好,错误。指向垃圾。这是我必须做的:

  void 
swap(MemRef& first,MemRef& second){
使用std :: swap;

// second是一个exref
if(second._ptr!= second._memory.c_str()){
swap(first._memory,second._memory);
swap(first._len,second._len);
swap(first._ptr,second._ptr);
}
// second是一个inref
else {
swap(first._memory,second._memory);
swap(first._len,second._len);
first._ptr = first._memory.c_str();
}
}



所有我可以得出结论是std :: swap


解决方案

随着问题的更新,我想我可以看到问题是什么=)



在您的初始 swap()函数中,您有以下行:

 交换(first._memory,second._memory); 
swap(first._ptr,second._ptr);
swap(first._len,second._len);

如果这些是exrefs,一切都很好 - 交换将按计划执行。但是,如果一个是inref(现在,我们将使用您提供的示例),然后这是进行:



在这些行:

  MemRef mr_a; // create an memref with _ptr(NULL),_len(0)
mr_a =woof;正如你所说,正确地说,从woof创建了一个临时 inref



< ,其 _ptr 变量指向 _memory.c_str()的开头。



现在,当 swap()被调用时,首先会发生这种情况:

  swap(first._memory,second._memory); 

到目前为止都很好。您已交换字符串 - 但其地址未更改,只有其内容。从标准:



引用
basic_string序列的元素的引用,指针和迭代器可能会被以下用途的
basic_string对象: - 作为非成员函数的参数swap()...
C ++国际标准n1905



现在, / p>

 交换(first._ptr,second._ptr); 

您介绍的是prolem。那些指向某处未定义 - 通过交换字符串,我们无效任何指针/迭代器/对字符串或其成员的引用,包括c_str() - 但我们肯定不交换记忆位置。所以,在这种情况下交换指针是错误的,正如你意识到的。



幸运的是,你已经解决了这个问题 - 通过重置指针而不是交换它们,避免指向无效的内存位置,并且所有问题都得到解决!希望这清除了发生了什么,虽然=)



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


I'm implementing the copy-and-swap idiom for operator= of a small non-owning-memory-referencing object I've designed. When MemRef is referencing a piece of a buffer whose lifetime I trust, _ptr points into the buffer, as you'd expect.

What is unusual about this MemRef is that it consists not only of a _ptr and a _len, but also a _memory std::string: there are certain users (or situations) of this class whom I do not trust to protect their memory; for them, I actually copy their memory into the _memory string during construction, and set _ptr = _memory.c_str(). I can always determine whether I have an "inref" MemRef (referring to its internal memory) or an "exref" MemRef (referring to some external buffer) by asking if _ptr == _memory.c_str().

I'm confused about how to write the swap routine. The following is taken from copy-and-swap idiom:

Here's operator=:

MemRef&
MemRef::operator=(MemRef other) { 
    swap(*this, other);
    return *this;
}

Here's the copy constructor:

// 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();
    }
}

And here's my swap(first, second) - which I believe needs more work.

void
swap(MemRef& first, MemRef& second) {
    using std::swap;
    swap(first._memory, second._memory);
    swap(first._ptr, second._ptr);
    swap(first._len, second._len);
}

So if I have:

MemRef mr_a("foo"); // creates an "inref" memref
MemRef mr_b(buffer_ptr, length); // creates an "exref" memref -> "blarch"
mr_a = mr_b;

operator=() gets called with a temporary MemRef built by copy-constructing mr_b; it calls swap(mr_a, mr_b_copy); swap() exchanges the pointer, length, and string (so that mr_a's former contents will be destructed along with mr_b_copy).

What I don't understand is whether the pointers in mr_a and mr_b_copy are correct at this point, or if they're tangled up with each other.

UPDATE 1: The above example doesn't illustrate the problem. Consider this one:

MemRef mr_a;  // creates a memref with _ptr(NULL), _len(0)
mr_a = "woof"; // 

For passing by value to operator=(), a temporary inref is constructed for "woof" and bound to the parameter other. Then, references to mr_a and to other are passed to swap() and bound as first and second respectively. After the swap, first._ptr was ... well, wrong. Pointing to garbage. Here's what I had to do:

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();
    }
}

All I can conclude is that std::swap(string, string) is doing something strange.

解决方案

With the update to the question, I think I can see what the problem is =)

In your initial swap() function, you had these lines:

swap(first._memory, second._memory);
swap(first._ptr, second._ptr);
swap(first._len, second._len);

If these were exrefs, all was well and good - swap would be executed as planned. However, if one was an inref (for now, we'll use the example you provided), then this was going on:

In these lines:

MemRef mr_a;  // creates a memref with _ptr(NULL), _len(0)
mr_a = "woof";

as you said correctly, a temporary inref was created from "woof", with its _ptr variable pointing to the beginning of _memory.c_str().

Now, when your swap() gets called, first this happens:

swap(first._memory, second._memory);

So far all good. You've swapped the strings - but their addresses haven't changed, only their contents. From the standard:

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

So now, during the line

swap(first._ptr, second._ptr);

you introduce the prolem. Those are pointing to somewhere undefined - by swapping the string, we invalidate any pointers/iterators/references to the string or its members, including c_str() - but we definitely don't swap the nemory locations. So, swapping the pointers is wrong in this case, as you realized.

Fortunately, you've already solved the problem - by resetting the pointers in the case of an inref instead of swapping them, you avoid pointing to invalidated memory locations, and all problems are resolved! Hopefully this clears up what was going on though =)

edit: added standard reference and clarified!

这篇关于对内部指针的对象实现swap()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆