2013-02-09 51 views
8

在蟒蛇,我一个不得不换2个变量的值,所有你需要做的是运行报表

x,y=y,x 

我们可以把它看成如果两个报表─(X = Y )和(y = x)并行执行,而不是一个接一个地执行。

有什么办法可以在C++中实现相同的效果吗?

注意/编辑:

我期待扩大这种“并行效应”(如果存在的话),以更复杂的表达式像
ones,twos= (ones^n)^~twos, (ones & n) | (twos & ~n);

这是可能的蟒蛇,这可能在c + +?

结论:

所以根据leemes和他的答案的评论给出了答案:

在C++ 03或

1.You可以使用Boost库2.您可以使用C++ 11

来访问std::tiestd::tuple以实现此“并行”效果。 至于目前,我标记为leemes答案被接受,但我仍然在寻找方法来实现这个很酷的功能在C++ 03中。

+3

'的std ::交换(X,Y);'是优选的方式。 – chris 2013-02-09 06:34:59

+3

@chris:实际上,'std :: swap(x,y)'是错误的***方式。 – Mehrdad 2013-02-09 07:19:59

+1

@Mehrdad,好点。我的重点是使用预制版本,而不是总是试图将其内联,但这是一个有效的问题。 – chris 2013-02-09 08:18:57

回答

18

特殊情况:交换两个变量

的值(对于一般的解决办法,见下文)

在C交换两个变量的值++,你应该总是使用swap

using std::swap; 
swap(x, y);  // Do NOT say: std::swap(x, y) -- Read about Koenig lookup! 

不要打扰如何它会这样做;它会这样做非常快。如果处理器支持它(但标准没有告诉实现这么做),C++标准库的实现将尽最大努力将其优化为单指令。对于只寄存器变量,例如有x86指令xchg,它将尽可能快地完成它。不要试图用一些“三个xor操作”来调整它,它不会更快。如果你不走运,它不会被优化到像xchg这样的东西。

C++ 03中的通用swap操作引入了一个临时变量并执行三个复制构造。在C++ 11中,存在移动语义,并且对象比被复制移动的更多。为了您自己的类型,假设其只持有一个指向实际数据的一些数据结构,你应该优化这个过程,使其在固定的时间进行:

  • 在C++ 03,您可以专门致力于std::swap或在您的名称空间(see the two top answers on this question)中实现您自己的swap函数来优化交换:只需交换班级中的每个成员即可交换其数据。对于仅保存指针的数据结构示例,只需交换指针即可。

  • 在C++ 11,也有新的移动语义,它允许你从一个到另一个对象,这将导致一个非常类似的行为,实现数据的移动。 (移动语义已经引入了更为普遍的问题,如交换两个对象:如果不再需要一个对象,但另一个对象必须是第一个对象的“复制”,则可以简单地移动它。)阅读有关移动语义和移动构造函数获取细节。

  • 对于两个C++ 03和C++ 11有另一种方式:您可以实现隐含共享数据写入时复制重类的数据结构等等。在上面的例子中,你的数据结构中包含一个指向实际数据的指针,实现引用计数。复制数据结构时,只需将参考计数器加1。修改数据时,请确保它不是共享的(ref count = 1),否则只能通过复制来“分离”它。这会导致定时复制和交换操作。


一般情况:多个任意表达式

对于其他命题与输入/输出相关的,像(a, b) = (x, y),只写他们“原样”,它将运行至少完美流水线,因为它们没有任何依赖性:

a = x; 
b = y; 

如果他们依赖于输入/输出,就像您在编辑中的示例,您可以将其分解并引入临时对象。你不会试图用诸如xor-ing等一些奇特的表达技巧来解决这个问题。编译器知道汇编程序的很多技巧(如xchg),你只知道用纯C++(如xor)表达的技巧。

在C++ 11,有std::tuplestd::tie允许你指定多个表达式,而不引入临时对象(它们将场景以保持存储在该元组中的值的后面被引入,并试图优化它们要么完全远离或在至少只使用寄存器如果可能的话,以将它们保持):

using std::tie; 
using std::make_tuple; 
tie(ones, twos) = make_tuple((ones^n)^~twos, (ones & n) | (twos & ~n)); 

。注意,类型的右手侧对/元组的有在左手侧匹配目标值作为转换不是隐含在这里。如果遇到问题,执行在右手侧的static_cast,告诉std::make_tuple明确的类型或只是使用的构造方法std::tuple需要明确的类型,如:

using std::tie; 
using std::tuple; 
tie(ones, twos) = tuple<int,int>((ones^n)^~twos, (ones & n) | (twos & ~n)); 
+0

任何人都知道在C++ 11之前是否存在'std :: tie'?我不确定。我原以为是这样,但谷歌在这方面并不健谈。它只在提升中可用吗? – leemes 2013-02-09 06:57:05

+1

否 - C++ 03没有std :: tie或元组(尽管Boost在C++ 03中实现了它们)。 – 2013-02-09 07:04:02

+0

@JerryCoffin谢谢指出;如预期的那样,除非你想在C++ 03中使用boost,否则只有C++ 11的一个很好的解决方案。 – leemes 2013-02-09 07:06:26

0

如果xy是纯整数,有各种快速技巧,以交换它们在一行:

http://cpptruths.blogspot.com/2006/04/swapping-two-integers-in-one-liner.html

+1

其中大多数会导致未定义的行为,即使它们不会,也不会比三行示例更快。 – 2013-02-09 06:42:27

+5

技巧很适合教育目的,代码测验和东西,但对于真正的代码使用'std :: swap'。 – leemes 2013-02-09 06:45:59