C++ 为什么std::swap有这么多专门化?
在查看的文档中,我看到了许多专门化。C++ 为什么std::swap有这么多专门化?,c++,templates,stl,swap,template-specialization,C++,Templates,Stl,Swap,Template Specialization,在查看的文档中,我看到了许多专门化。 看起来每个STL容器以及许多其他std设施都有专门的交换。 我以为有了模板的帮助,我们就不需要所有这些专门化了 例如, 如果我编写自己的对它可以正确地与模板版本配合使用: template<class T1,class T2> struct my_pair{ T1 t1; T2 t2; }; int main() { my_pair<int,char> x{1,'a'}; my_pair<in
看起来每个STL容器以及许多其他std设施都有专门的交换。
我以为有了模板的帮助,我们就不需要所有这些专门化了 例如,
如果我编写自己的
对
它可以正确地与模板版本配合使用:
template<class T1,class T2>
struct my_pair{
T1 t1;
T2 t2;
};
int main() {
my_pair<int,char> x{1,'a'};
my_pair<int,char> y{2,'b'};
std::swap(x,y);
}
我还想知道是否应该为自定义类编写自己的专门化,或者仅仅依赖于模板版本 那么从std::pair中获得了什么呢 表演。通用交换通常足够好(从C++11开始),但很少是最优的(对于
std::pair
,以及大多数其他数据结构)
我还想知道是应该为自定义类编写自己的专门化,还是仅仅依赖模板版本
我建议默认情况下依赖模板,但是如果分析显示它是一个瓶颈,那么要知道可能还有改进的余地。过早优化和所有这些…这大概是出于性能原因,因为
对包含的类型交换成本低,但复制成本高,如vector
。由于它可以在第一次
和第二次
上调用swap,而不是使用临时对象进行复制,因此它可以显著提高程序性能。std::swap
按照以下代码执行:
template<typename T> void swap(T& t1, T& t2) {
T temp = std::move(t1);
t1 = std::move(t2);
t2 = std::move(temp);
}
如您所见,swap
使用ADL直接在对中的元素上调用:这允许在第一个
和第二个
上使用swap
的定制且可能更快的实现(这些实现可以利用元素内部结构的知识来获得更高的性能)
(有关更多信息,请参阅。)交换两对向量的最有效方法与交换两个向量的最有效方法不同。这两种类型具有不同的实现、不同的成员变量和不同的成员函数
以这种方式“交换”两个对象并没有通用的方法
我的意思是,当然,对于可复制类型,您可以这样做:
T tmp = a;
a = b;
b = tmp;
但那太可怕了
对于可移动类型,您可以添加一些std::move
并防止复制,但接下来的一层仍然需要“交换”语义,以便实际具有有用的移动语义。在某些情况下,您需要专门研究。原因在于性能,尤其是c++11之前的版本
考虑类似“向量”类型的东西。向量有三个字段:大小、容量和指向实际数据的指针。复制构造函数和复制赋值复制实际数据。C++11版本还有一个移动构造函数和移动赋值,用于窃取指针,将源对象中的指针设置为null
专用向量交换实现可以简单地交换字段
基于复制构造函数、复制赋值和析构函数的通用交换实现将导致数据复制和动态内存分配/释放
基于move构造函数、move赋值和析构函数的通用交换实现将避免任何数据复制或内存分配,但它将保留一些冗余的零位和零位检查,优化人员可能无法优化这些检查
那么,为什么要对“配对”进行专门的交换实施呢?对于一对int和char,没有必要。它们是普通的旧数据类型,所以通用交换就可以了
但是如果我有一对向量和字符串呢?我想使用这些类型的专家交换操作,所以我需要交换一对交换类型,通过交换它的组成元素来处理它。 < P>有一条规则(我认为它来自于萨特的特殊的C++或Scott Meyer的有效C++系列)。如果您的类型可以提供不抛出的交换实现,或者比泛型的std::swap
函数更快,那么它应该作为成员函数void swap(T&other)
这样做
从理论上讲,通用的std::swap()
函数可以使用模板魔术来检测成员交换的存在,并调用它,而不是执行此操作
T tmp = std::move(lhs);
lhs = std::move(rhs);
rhs = std::move(tmp);
但是似乎没有人考虑过这个问题,因此人们倾向于添加freeswap
的重载,以便调用(可能更快的)成员swap。在容器上实现的swap()
方法可以利用容器的内部结构,因此效率更高(例如std::list
只需交换指针和大小)。std::swap
可在模板中使用当您不知道容器类型时。std::swap
的专业化可以调用容器方法来利用更高效的部署。我怀疑在移动语义之前,差异要大得多。在此之前,访问容器内部意味着只需切换指针,而通用路由(无特殊编译器支持)可能需要进行大量复制。它们是重载,而不是模板专门化。交换一对可能会很痛苦。您需要做的第一件事是从树中取出dang partridge…大多数时候,我发现自己编写了一个交换重载,我这样做是因为我想利用。感谢这个具体的示例显式元素交换也可能比临时变量方法慢。例如类Foo{char a,b,c,d,e,f,g,h;};
(好的,疯狂的类型,但请注意)。此类有一个默认的复制构造函数和一个空的析构函数。默认的复制构造函数相当于memcpy(dest,src,sizeof(Foo));
将编译为单个64位加载和存储。因此,临时变量交换将编译为三条或六条指令。基于元素的
T tmp = a;
a = b;
b = tmp;
T tmp = std::move(lhs);
lhs = std::move(rhs);
rhs = std::move(tmp);