为什么每个STL容器都有一个定义为成员函数的交换函数?

Aay*_*jan 8 c++ stl

考虑queueSTL中的容器.

据我所知,标题中的swap()可用效果<algorithm>很好.

我理解swap()只会queue表面复制实例,也就是说,只会复制frontrear指针size,以及其他数据成员.

两个队列中的条目不会在物理上交换位置,但我不明白为什么在任何情况下这都是必要的,因为一旦指针和大小被交换,两个队列将被有效地交换.

Rei*_*ica 4

在C++11引入移动语义之前,泛型实现std::swap别无选择,只能做两份副本。从概念上讲,这是:

template <class T>
void swap(T &a, T &b)
{
  T t(a);
  a = b;
  b = t;
}
Run Code Online (Sandbox Code Playgroud)

请注意,这个泛型std::swap不知道有关传入对象的内部的任何信息(例如,因为可以使用任意用户类型调用它),因此必须进行复制。请注意,对于容器来说,这意味着复制元素。

swap因此,提供一个仅重新指向一些内部指针的优化成员函数是一个巨大的性能胜利。

由于引入了移动语义,因此使用移动可以使通用交换更加高效。再次,从概念上讲:

template <class T>
void swap(T &a, T &b)
{
  T t(::std::move(a));
  a = ::std::move(b);
  b = ::std::move(t);
}
Run Code Online (Sandbox Code Playgroud)

当然,在实践中,它可能对涉及非抛出的移动操作以及各种额外位有要求。

有了移动语义,优化后的成员版本可能就没有以前那么重要了。但是,在了解类型的确切实现细节的情况下,交换它仍然可能比三个通用移动更快。


除了上面的讨论之外,请注意std::swap标准库中定义的几乎所有类型都存在特定于类型的重载。这些重载所做的只是swap在操作数之一上调用优化的成员函数。这样,您就拥有了两全其美的优点:一个通用的自由函数swap,可以用任何东西调用,但它对标准库所知道的所有内容都有优化的实现。

可以放弃成员函数并std::swap直接在重载内提供优化的实现,但这意味着它们可能需要成为好友,并且可能被认为对用户代码来说更难访问。

  • 尽管如此,成员“swap”比 3 步“std::swap”更高效。 (2认同)