为什么每个STL容器都有一个定义为成员函数的交换函数?
考虑STL中的queue
容器。
据我的理解, <algorithm>
头文件中提供的swap()
可以正常工作。
我知道swap()
只会表面复制queue
实例,也就是说,只有front
和rear
指针会随着size
和其他数据成员一起被复制。
两个队列中的条目不会在物理上交换位置,但我不明白为什么在任何情况下都需要这样做,因为一旦交换了指针和大小,两个队列就会有效地交换。
在C ++ 11引入移动语义之前, std::swap
的通用实现别无选择,只能做两个副本。 从概念上讲,这是:
template <class T>
void swap(T &a, T &b)
{
T t(a);
a = b;
b = t;
}
请注意,这个通用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);
}
当然,在实践中,它可能对涉及非投掷的移动操作以及各种额外的比特有要求。
随着移动语义的到位,优化的成员版本可能不像以前那么重要。 但是在知道某个类型的确切实现细节后,仍然有可能通过交换它可以比三种通用移动更快。
除了上面的讨论外,请注意标准库中定义的几乎所有类型都存在std::swap
类型特定的重载。 这些重载所做的只是在其中一个操作数上调用优化的swap
成员函数。 这样,你就拥有了两全其美的优势:一个通用的免费函数swap
,可以用任何东西调用,但是它为标准库知道的所有东西都优化了实现。
可以放弃成员函数并直接在std::swap
重载内提供优化实现,但这意味着他们可能需要成为朋友,并且可能被认为对用户代码更糟糕。
由于免费的std::swap
对每个容器都有重载,所以成员函数swap
并不是真的必要。 免费的重载可以被声明为friend
并执行所有特定于实现的特定于容器的魔术来实现高效的交换。
实际上,它们调用成员swap
s。 我想这可以提高如何调用这些函数的灵活性,并且可以节省大量的friend
声明。
我不知道还有比这更多的东西。
当统一调用语法提议(Bjarne Stroustrup 2014版)最终被采用时,经过一些最终调整后,您的问题将变得毫无意义,因为std::swap(my_queue, another_queue)
和my_queue.swap(other_queue)
很可能会完全相同功能的别名。 不幸的是,C ++ 17不会发生这种情况。 也许在C ++ 20中? 人们可以梦想...
上一篇: Why does every STL container have a swap function defined as a member function?
下一篇: Docker Nginx stopped: [emerg] 1#1: host not found in upstream