有没有一种优雅的方式来交换C ++中的引用?

时间:2014-09-12 09:17:32

标签: c++ reference swap unions

有时类会引用其他类。为这些类实现std::swap()不是直截了当的,因为它会导致交换原始实例而不是引用。下面的代码说明了这种行为:

#include <iostream>

class A
{
   int& r_;
public:
   A(int& v) : r_(v) {}
   void swap(A& a)
   {
      std::swap(r_, a.r_);
   }
};

void test()
{
   int x = 10;
   int y = 20;

   A a(x), b(y);
   a.swap(b);

   std::cout << "x=" << x << "\n"
             << "y=" << y << "\n";
}

int main()
{
    test();
    return 0;
}

使用union的简单解决方法:

class A
{
   union
   {
      int& r_;
      size_t t_;
   };
public:
   A(int& v) : r_(v) {}
   void swap(A& a)
   {
      std::swap(t_, a.t_);
   }
};

这很有效,但并不帅。有没有更好的方法来交换C ++中的两个引用?另外,C ++标准如何解释在一个联合中混合引用和值,考虑到在Stroustrup的&#34; C ++编程语言&#34; 预订&#39;参考& #39; 被定义为对象的&#39;替代名称,别名&#39; (第189页)。

4 个答案:

答案 0 :(得分:22)

你正在使用的联合技巧就像代码获取一样不可移植。该标准对编译器如何实现引用没有没有任何要求。他们可以(并且很可能)使用引擎盖下的指针,但这绝不保证。更不用说sizeof(size_t)sizeof(T*)无论如何都不需要相等。

您的问题的最佳答案是:如果您需要可分配/可交换的类,请不要使用引用成员。只需使用指针成员即可。毕竟,根据定义,引用是不可重载的,但是由于需要可交换的类,您需要一些可重命名的东西。那是一个指针。

答案 1 :(得分:7)

您可以使用std::reference_wrapper代替直接引用(您不能swap)或指针(可能是nullptr)。类似的东西:

class A
{
    std::reference_wrapper<int> r;
public:
   A(int& v) : r(v) {}
   void swap(A& rhs)
   {
      std::swap(r, rhs.r);
   }

   int& get() const { return r; }
};

Live example

答案 2 :(得分:5)

使用union的程序不合法,因为您分配了引用但交换整数而不是打算再次使用引用。你可以在这里阅读:Accessing inactive union member and undefined behavior?

这里一个简单的解决方案是使用指针而不是引用。一切都会顺利进行,没有特殊的代码。如果你真的不喜欢这个,也许你可以使用boost::optional<int&>而不是简单的引用,但我很难看出它会如何变得更好。

答案 3 :(得分:0)

如果我理解你的例子,基本上你想要做的是重新引用引用。这是你无法用C ++做的。您可以在引用的对象中交换,也可以使用指针。