【问题标题】:Are there any downsides to using `std::reference_wrapper<T>` as an always-valid member variable instead of a pointer?使用 `std::reference_wrapper<T>` 作为始终有效的成员变量而不是指针有什么缺点吗?
【发布时间】:2021-03-08 10:45:58
【问题描述】:

我遇到了一个很常见的问题。我有一个类必须存储指向不同类对象的非拥有指针。

我知道:

  • 保证引用对象的生命周期比实例长。
  • 引用的对象在构造函数中传递,除了移动或赋值外不会发生变化。
  • 它永远不会无效。
  • 它用于多种方法。
  • 它可以被多个实例共享。

想想例如logger 非全局类。

这些点引导我使用一个保证有效性的参考变量来解决这个问题:

struct Foo{};

struct Bar{
    Bar(Foo& foo):m_foo(foo){}

Foo& m_foo;
};

最大的缺点是 Bar 不必要地几乎是不可变的 - 没有分配,没有移动。

我所做的通常是将Foo 存储为指针。这解决了大多数问题,只是不再很清楚指针始终有效。此外,它增加了一个新的小问题,它可以在任何方法中失效,这不应该发生。 (将其设为 const 与 &amp; 具有相同的缺点)。这让我在每一种方法中都添加了assert(m_foo),以便安心。

所以,我想只存储std::reference_wrapper&lt;Foo&gt;。它总是有效的并且它保持Bar 可变。与简单的指针相比有什么缺点吗? 我知道任何方法仍然可以 指向例如一个局部变量,但假设这不会发生,因为可能很难获得Foo 的新有效实例。至少比简单的难=nullptr;

我知道这种方法用于std::vector 之类的容器,所以我认为这没问题,但我想知道是否有任何我应该寻找的问题。

【问题讨论】:

标签: c++ c++11


【解决方案1】:

由于Foo 是一个结构,因此每次访问Foo 的任何成员或字段时都需要调用get()。使用引用或指针,您可以使用“。”或 '->' 分别用于成员访问。所以reference_wrapper 在这方面不是“透明的”。 (目前也没有办法在 C++ 中使其“透明”,这当然很好)。

不会有运行时开销,但代码会因get() 调用而拥塞。

如果这不是您所关心的,那么使用reference_wrapper 代替指针没有任何缺点。 (其实reference_wrapper是通过指针成员实现的)

编辑:如果您只需要调用Foo 的一个或两个成员函数,则可以从reference_wrapper 继承并添加一个调用存根。但这可能有点矫枉过正......

【讨论】:

  • 是的,这是关于 . 不可重载和 */-&gt; 不适合非指针。通过利用隐式上下文转换到T&amp;,减少了get() 的拥塞。
  • 好吧,也许有一天operator . 的提案会有所收获!
  • @Quimby Overloading '->' 会起作用,但也许一开始就可以使用指针。操作员 '。'是不可重载的,有建议(甚至是 Stroustrup 提出的)但没有成功。如果您只需要为 'Foo' 调用成员函数,则可以从 reference_wrapper 继承并添加一个存根成员。不过,这对数据成员不起作用。
  • 好的,谢谢大家的帮助,我就坚持一下指针。
  • @Quimby 可以理解,我也会使用指针 :-)
猜你喜欢
  • 1970-01-01
  • 2015-10-01
  • 2012-11-19
  • 2021-04-21
  • 1970-01-01
  • 2019-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多