异或交换
我们通常会遇到这样的面试题:
- 请编写一个函数,交换 a、b 两个变量,且不能使用额外的临时变量。
通常答案是这样的:
#define SWAP(a,b) do { \
(a) ^= (b); \
(b) ^= (a); \
(a) ^= (b); \
} while(0)
在面试的时候,这个答案或许是满意的。
《Linux 多线程服务端编程:使用 muduo c++ 网络库》的作者陈硕在书中(P501)指出:
- 这个所谓的“技巧”在现代的机器上只会更慢。原始办法是两次内存读和写,这个“技巧”是六读三写加三次异或。
- 同样也不能节省内存,因为中间变量tmp通常会是寄存器。就算它在函数的局部堆栈上,反正栈已经开在那儿了,也没有进一步的函数调用,根本节约不了一丁点内存。
- 相反,由于计算步骤较多,会使用更多的指令,编译后的机器码长度会增加。
C 语言对策
#define SWAP(a,b) do { \
typeof(a) _a = (a); \
typeof(b) _b = (b); \
(void)( &_a == &_b ); \
(a) = _b; \
(b) = _a; \
} while(0)
- 第2行定义变量 _a,第3行同理。
- 第4行,通过比较 _a 和 _b 的地址,检查他们的类型是否相同。如果类型不相同,则会在编译时出现 error 或者 warming。之所以加 (void),也是为了防止编译器 warming。
- 第5、6行实现交换两个变量。
虽然步骤多了,临时变量多了;但是多了类型判断,有得有失。
C++ 语言对策
在 c++ 编程中,交换两个变量就方便的多了。
我们可以使用 STL 的通用工具 swap。它的定义在< utility >中
template <typename T>
inline void swap(T& a, T& b) {
T tmp(std::move(a));
a = std::move(b);
b = std::move(tmp);
}