为什么交换在C ++中不使用Xor操作

问题描述 投票:10回答:5

我了解到Xor操作可用于实现有效的交换功能。像这样:

template<class T>
void swap(T& a, T& b)
{
    a = a^b;
    b = a^b;
    a = a^b;
}

但是我在互联网上可以找到的所有交换的实现本质上是这样的:

template<class T>
void swap(T& a, T& b)
{
    T temp(a);
    a = b;
    b = temp;
}

似乎编译器没有为上述两种形式生成相同的代码,因为我在VC ++ 2010上对其进行了测试,并且第一个完成得更快(并且比std :: swap更快)。第一个有便携式或其他任何问题吗?可以纠正我的任何错误,因为我不是英语母语人士,也不擅长C ++。

c++ swap xor micro-optimization premature-optimization
5个回答
19
投票

我知道Xor操作可用于实现有效的交换功能

恐怕你学错了。 XOR交换已过时:如果可靠地比使用临时值快,那​​么它就不应该在现代的编译器和处理器上使用(“现代”指的是大约20年或更长时间)。您说这对您来说更快,也许您应该显示基准代码,看看其他人是否得到相同的结果。

除了您的代码仅适用于整数类型之外,它还具有一个基本的错误。尝试使用您的swap版本:

int a = 1;
swap(a,a);
std::cout << a << '\n';

10
投票

并且效果取决于您在哪里使用它。

在普通cpu上,两个整数变量的普通交换看起来像

$1 <- a
$2 <- b
a <- $2
b <- $1

4个操作,2个加载,2个存储,并且最长依赖项是2

以异或方式:

$1 <- a
$2 <- b
$3 <- $1 ^ $2
$4 <- $3 ^ $2
$5 <- $3 ^ $4
a <- $5
b <- $4

7个操作,2个加载,2个存储,3个逻辑,并且最长依赖性为4

因此,至少在正常情况下,即使使用xor交换也较慢。


4
投票

我认为最明显的原因是XOR运算符仅对整数类型有意义。


2
投票

当然,因为xor技巧适用于POD类型。

如果要交换两个用户定义的复杂类型,则xor将不起作用。您需要原始存储器的深层副本,而不是直接副本,这类似于xor所做的。

编辑:

我在VC ++ 2010上进行了测试,第一个完成速度更快(并且比std :: swap更快)。

真的吗?您是否在调试模式下编译?您的结果如何?


0
投票

首先,仅对整数类型定义XOR运算符。

第二,您可以使用强制转换技巧将非整数类型转换为整数形式。

但是,除POD类型外,所有其他类型都会导致未定义的行为,

第四,对于XOR操作的大小/对齐方式没有很好的支持的类型,将需要更多的调整(循环是最不邪恶的)。

您可能使operator^重载,但这意味着swap()的每个特殊化都必须确保它的存在或定义一个,并且这可能会使名称查找产生比其价值更大的混乱。当然,如果已经存在这样的运算符,则它不一定具有正确的行为,并且由于这种重载不一定是inlineconstexpr,您可能会因此而获得较差的性能。

© www.soinside.com 2019 - 2024. All rights reserved.