可以std :: string重载"substr"为rvalue*this并窃取资源吗?

Joh*_*itb 21 c++ substr rvalue-reference c++11

它只是发生在我身上,我注意到std::stringsubstr操作可能是右值更有效时,它可以盗取分配的内存*this.

N3225的标准库包含以下成员函数声明 std::string

basic_string substr(size_type pos = 0, size_type n = npos) const;
Run Code Online (Sandbox Code Playgroud)

可以实现substr针对rvalues 优化的实现是否会重载并提供两个版本,其中一个版本可以为rvalue字符串重用缓冲区?

basic_string substr(size_type pos = 0) &&;
basic_string substr(size_type pos, size_type n) const;
Run Code Online (Sandbox Code Playgroud)

我想rvalue版本可以实现如下,*this将设置的内存*this重用于移动状态.

basic_string substr(size_type pos = 0) && {
  basic_string __r;
  __r.__internal_share_buf(pos, __start + pos, __size - pos);
  __start = 0; // or whatever the 'empty' state is
  return __r;
}
Run Code Online (Sandbox Code Playgroud)

这是否在常见的字符串实现上以有效的方式工作,还是会占用过多的内务管理?

Ant*_*ams 4

首先,实现不能添加窃取源的重载,因为这是可以检测到的:

std::string s="some random string";
std::string s2=std::move(s).substr(5,5);
assert(s=="some random string"); 
assert(s2=="rando");
Run Code Online (Sandbox Code Playgroud)

如果实现窃取了数据,第一个断言就会失败s,并且 C++0x 措辞本质上禁止写入时复制。

其次,这不一定是一种优化:您必须添加额外的内务处理std::string来处理它是较大字符串的子字符串的情况,这意味着当不再有任何字符串引用时要保留大块大字符串,只是它的一些子字符串。

  • @Anthony,n3225 说“如果函数参数绑定到右值引用参数,则实现可能会假设此参数是对此参数的唯一引用。”。这是否不适用于通过重载决议添加的成员函数的隐式对象参数?当我们说“std::move(s).substr(...)”,然后仍然使用“s”时,在我看来我们会违反这个假设。 (4认同)
  • 这不是真的,因为 `::std::move` 基本上是在说“请从源中窃取数据,这样就可以了!”。 (2认同)
  • 是的,但是 `std::move(s).substr(..)` 不会将任何内容绑定到右值引用**参数**。`std::move` 接受左值引用并创建右值引用。`substr` 是一个 `const` 成员函数,因此隐式对象参数是一个 `const` 左值引用。正如我已经说过的,这与 `s2=std::move(s)` 有很大不同,其中 `s` **绑定到 `operator=` 的右值引用参数。 (2认同)