为什么我需要在临时 dynamic_bitset 上调用 std::move?

Why do I need to call std::move on a temporary dynamic_bitset?

我在这里讲一个冗长的背景故事,因为除了直接回答之外,我还想知道我导致这种情况的推理是否正确。

我有一个接受 dynamic_bitset<> 参数的函数(来自 Boost.dynamic_bitset)。 说它看起来像这样。

void foo(boost::dynamic_bitset<> db) {
    // do stuff
}

碰巧它只被临时调用,从构造函数构建,如foo(boost::dynamic_bitset<>{5}.set())(调用所有位设置的 5 位位集)。

我的位集只有少量的位(少于 32)。所以一开始,我想 "I'll just pass it by value; the copy is smaller than a pointer." 但后来我想 "It's dynamic, so it must allocate space on the heap. I want to avoid unnecessary allocations and frees."

所以,我可以做到

void foo(const boost::dynamic_bitset<>& db);

但是引用是一个指针,dynamic_bitset(大概)有一个指向它的数据的指针,所以在 foo 中使用 db 会经历两个间接级别,这看起来很愚蠢。显然,最好的方法是将指向数据的指针复制到 foo,而无需重新分配和复制堆上的数据。

"Aha!"我说。 "Surely this is what move semantics are for." 所以,我把签名改成

void foo(boost::dynamic_bitset<>&& db);

但是,调用 foo(boost::dynamic_bitset<>{5}.set()) 会出现编译错误,cannot bind 'boost::dynamic_bitset<>' lvalue to 'boost::dynamic_bitset<>&&'。 我必须改为打电话 foo(std::move(boost::dynamic_bitset<>{5}.set())) 然后一切正常。

为什么我需要调用std::move? 这看起来很明显是一个 xvalue(即将过期的临时值),不是吗?

来自the boost docs

dynamic_bitset& set();

set() returns 一个左值。

一般来说,如果函数 returns 按值,或按右值引用:

dynamic_bitset   set();
dynamic_bitset&& set();

那么表达式 set() 是一个右值(在第一种情况下是纯右值,在第二种情况下是亡值)。但是因为在实际代码中 set() returns 是一个左值引用,表达式 set() 是一个左值。

category values http://downloads.sehe.nl/Whosebug/value-categories.svg