【问题标题】:Initialize reference member by new() call通过 new() 调用初始化引用成员
【发布时间】:2019-02-28 15:30:12
【问题描述】:

这样的初始化很糟糕吗?

class A
{
public:
    ~A();
    A();

    B &b;
};

A::~A()
{
    delete &b;
}

A::A() :
     b(*(new B()))
{
}

我想要的只是在没有“->”运算符的情况下访问成员“b”。我也不能让 B 类成为 A 类的一部分,因为 B 类在 A 类的标题中不完整。

更新:感谢您的回答!如果您需要更多信息,这里的 B 类代表一个“信号”(回调列表)。在 99% 的情况下,这个类只是其他类的成员(不是指针或引用)。但是一个特定的类(在我的示例中为 A)不能包含 B 类标头。我仍然希望 A 类中的这个信号能够像任何其他信号一样被连接和调用:

object->signal.connect(...);
object->signal();

使用点,而不是“->”。 A 类不能包含 B 类标头,因为有模板类继承了 A 类...

【问题讨论】:

  • 为什么要在没有->的情况下访问它?
  • Also I can't make class B to be part of class A because class B is incomplete in A class' header.转发声明吗?
  • 这种设计介于怪异和危险之间
  • 如果您使用this technique,您可以在A 中有一个引用,而不是将其绑定到您动态初始化的内容。
  • @CoryKramer :我目前正在维护一个代码库,它使用这个,呃,“概念”作为其“内存管理技术”之一(当然是 C++11 之前的)。这会导致您不知道是否应该使用delete 的引用。

标签: c++


【解决方案1】:

引用成员破坏了赋值运算符的语义:它不会重置引用,这与指针不同。它还破坏了移动构造函数和赋值。并且不能取引用成员的 sizeof 或地址。

在我看来,永远不要使用引用成员,因为它们不会增加任何价值,只会引入限制。

Bjarne Stroustrup 在“C++ 的设计和演变”中解释说,将引用引入 C++ 是为了允许运算符重载和有效的参数传递。这就是引用不能为空(它指的是表达式操作数或调用参数)并且具有所有这些特殊的非值类型语义的原因。使用参考成员的人将参考应用于参考并非旨在解决的问题。

使用分配new 表达式的结果初始化引用是要求内存泄漏,因为引用(伪)析构函数什么都不做(它不会为您调用delete)。

【讨论】:

  • 可能不是这个论点的正确位置,但是你为什么引用成员不好的两个观点都被“如果只通过(智能)指针使用类也没关系”来反驳,对于不属于您的公共 API 的某些内容,很可能就是这种情况。并且与(智能)指针不同,引用成员传达了明确的保证,即它在类的整个生命周期内都可用(并且非空)(悬空状态无关紧要,因为指针成员也是如此)。
  • @MaxLanghof 我认为拥有参考成员没有价值,只有限制。
  • 感谢您的意见。我想要的只是在没有“->”的情况下访问这个成员。我更新了问题以解释原因。但似乎我需要其他解决方案......
【解决方案2】:

“这样的初始化很糟糕吗?” - 不,这不是非常糟糕。这有点不寻常且不习惯,并且可能会(相当)引起一些眉毛。我会说,这是中等程度的糟糕,而且似乎没有必要,至少考虑到所提供的信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-12-08
    • 1970-01-01
    • 2015-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多