【问题标题】:std::list::splice, list&& VS list&std::list::splice, list&& VS list&
【发布时间】:2012-12-05 23:00:53
【问题描述】:
std::list 的一些方法,可能还有其他 STL 容器,在 C++11 中添加了新的重载。我需要的是list::splice()。一种方法采用 list& 参数,另一种采用 list&& 参数。
我想知道有什么区别,我应该更喜欢哪一种。
我查看了 libstdc++(GCC 编译器使用的标准 C++ 库)的实现,它在两种情况下都在内部使用了 list&& 版本。 C++11 规范也没有说明这个问题。它只是提供了 2 种方法,没有解释其中的区别。
您不移动列表本身,也不移动节点(复制它们的指针似乎是将节点从一个列表移动到另一个列表的方式),那么这有什么关系呢?我只有一个想法,也许使用 list&& 就像对编译器的承诺,你不再需要另一个列表,编译器可以保存一些操作,因为它不必保持另一个列表有效......
【问题讨论】:
标签:
c++
stl
c++11
move-semantics
【解决方案1】:
你不需要太在意。当您传递的参数是右值时,将选择带有 std::list&& 参数的重载 - 通常当它引用的对象是临时对象时。您无需明确说明要使用哪个重载。
存在这两个版本的函数的原因是为了方便,因此客户端不必在将临时对象传递给 splice 之前从临时对象创建一个 temp std::list 变量(感谢 cmets 中的 @HowardHinnent) .
此外,当您从中拼接的列表是一个临时对象时,关心维护它的状态是没有意义的。函数的&& 版本可能只是从该列表中撕下胆量,在地板上留下一团糟。这可能是为了提高效率(但实际上,std::list 没有太多理由这样做)。
如果你有一个std::list、other,你知道你永远不会再使用它,你可以自愿说“我不在乎你用它做什么”,使用std::move:
l.splice(pos, std::move(other));
表达式std::move(other) 是一个右值,因此splice 函数会将其视为临时值。
【解决方案2】:
左值引用绑定到左值,右值引用绑定到右值:
tyedef std::list<Foo> lt;
lt make_list();
int main()
{
lt x;
lt tmp = make_list();
x.splice(tmp); // needs '&'
x.splice(make_list()); // needs '&&'
}