为什么 C++23 string::resize_and_overwrite 将操作作为右值调用?

康桓瑋*_*康桓瑋 14 c++ string c++23

为了提高写入数据的性能std::string,C++23专门引入resize_and_overwrite()std::string. 在[字符串.容量]中,标准描述如下:

\n
\n
template<class Operation>\nconstexpr void resize_and_overwrite(size_type n, Operation op);\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. \n

    \xe2\x80\x94o = size()在调用之前resize_and_overwrite

    \n

    \xe2\x80\x94kmin(o, n)

    \n

    \xe2\x80\x94p是 a charT*,使得范围 [ p, p + n] 有效并且this->compare(0, k, p, k) == 0true调用之前。p + k[ , ]范围内的值p + n可能是不确定的[basic.indet]

    \n

    \xe2\x80\x94OP是表达式std::move(op)(p, n)

    \n

    \xe2\x80\x94r = OP

    \n
  2. \n
\n

[...]

\n
    \n
  1. 效果:计算,用 [ , )OP替换 的内容,并使 [ , ]范围内的所有指针和引用无效。*thispp + rpp + n
  2. \n
\n
\n

但我发现这个函数在调用它之前将用于std::move转换op为右值,这意味着我们不能传入仅重载左值的可调用对象operator()demo):

\n
#include <string>\n\nint main() {\n  struct Op {\n    int operator()(char*, int) &;\n    int operator()(char*, int) && = delete;\n  } op;\n  std::string s;\n  s.resize_and_overwrite(42, op); // ill-formed\n}\n
Run Code Online (Sandbox Code Playgroud)\n

这种行为似乎有点奇怪,但由于此更改是在上一版本中进行的\n论文的

\n

那么,这背后有哪些考虑呢?op必须作为右值调用的任务有什么好处吗?

\n

T.C*_*.C. 11

op在被销毁之前只调用一次,因此将其作为右值调用允许&&对其进行任何重载以重用它可能持有的任何资源。

可调用对象在道德上一个 xvalue - 它是“过期”的,因为它在调用后立即被销毁。如果您专门设计了可调用对象以仅支持作为左值调用,那么库很乐意阻止其工作。