【问题标题】:Is there an elegant way to swap references in C++?有没有一种优雅的方式来交换 C++ 中的引用?
【发布时间】:2014-09-12 09:17:31
【问题描述】:

有时类会引用其他类。为此类类实现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;
}

使用联合的简单解决方法:

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

这很有效,但并不美观。有没有更好的方法在 C++ 中交换两个引用?此外,考虑到在 Stroustrup 的 “C++ 编程语言” 书中,'reference' 被定义为一个 ,C++ 标准如何解释在一个联合中混合引用和值'对象的替代名称,别名' (p.189)。

【问题讨论】:

  • 简而言之,不要将引用成员用于应该完全可交换的对象。引用不是指针。别再希望他们是了。
  • +1 这个问题写得很好,并且有一个清晰、小而有效的例子。但是,不要在生产代码中使用它。听从 Angew 的建议
  • “交换两个引用”是什么意思?引用是对象的别名,所以除了交换对象之外的任何事情都会很奇怪。将引用视为指针只会增加混乱。
  • @juanchopanza:不完全是。在同一本 Stroustrup 书中,讨论了引用的属性,交换两个引用的想法与这些属性中的任何一个都不矛盾。这不像您将引用分配给彼此。对象的数量和引用被初始化的事实保持不变。
  • @bkxp 交换引用除了交换它们引用的对象之外没有任何意义。也许您可以详细说明这有什么其他含义。

标签: c++ reference swap unions


【解决方案1】:

您使用的联合技巧与代码一样不可移植。该标准对编译器如何实现引用没有任何要求。他们可以(并且很可能会)在后台使用指针,但这永远不能保证。更不用说sizeof(size_t)sizeof(T*) 无论如何都不需要相等。

您的问题的最佳答案是:如果您需要可分配/可交换的类,请不要使用参考成员。只需使用指针成员即可。毕竟,根据定义,引用是不可重新安装的,但是通过希望类可交换,您需要一些可重新安装的东西。这是一个指针。

【讨论】:

  • 最初,我希望编译器不允许在一个联合中混合引用和非引用。这就是我问题的最后一部分的来源。
  • @bkxp:答案是它无效,编译器不应该允许它。我的没有:ideone.com/68kzZq
【解决方案2】:

您可以使用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

【讨论】:

  • 这是一个很好的例子,谢谢。标准社区似乎已经意识到交换引用的必要性,并在 C++11 中添加了一种解决方法,这与此处其他一些答案中表达的观点相反,即交换引用是“坏语气”,应该避免。看看这是如何实现的会很有趣。可能它是编译器内在的,因为点访问运算符不能被重载,并且没有点访问引用包装器将几乎没有可用性。
  • @bkxp:不需要内在的,一个简单的指针成员就可以完成这项工作。
  • @bkxp 这不是为交换引用而添加的;添加它是为了在 std::bind()std::thread 等上下文中通过活页夹将引用传输到函数中。
  • @bkxp 请注意,实际上,您无法通过在引用包装器上使用. 来访问引用包装器所引用的对象的成员。
  • 您可以通过添加operator int 来改进这一点。当然r 在课堂外是只读的。
【解决方案3】:

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

这里一个简单的解决方案是使用指针而不是引用。然后一切都会顺利进行,无需特殊代码。如果你真的不喜欢这个,也许你可以使用boost::optional&lt;int&amp;&gt; 而不是简单的引用,但我很难看到这样会更好。

【讨论】:

    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-24
      • 2016-09-13
      • 2019-01-12
      • 2010-09-07
      相关资源
      最近更新 更多