使用引用相对于使用指针的优势是否证明偶尔"null-references"是合理的?

Do the advantages of using references over using pointers justify occasional "null-references"?

本文关键字:null-references 偶尔 是否 相对于 引用 指针 证明      更新时间:2023-10-16

我目前正在设计一个大致如下所示的类层次结构:

struct Protocol
{
    // Pass lower-layer protocol as a reference.
    Protocol(Protocol & inLLProtocol) :
        mLLProtocol(inLLProtocol)
    {
    }
    // A protocol "always" has a LLProtocol.
    Protocol & mLLProtocol; 
};

struct Layer1Protocol : Protocol
{
    // This is the "bottom" protocol, so I pass a fake reference.
    Layer1Protocol() : Protocol(*static_cast<Protocol*>(nullptr)) {}
};

IIRC 将引用绑定到*nullptr是安全的,只要从不访问引用。因此,现在我有责任以这样的方式设计我的 Layer1Protocol 类来防止这种情况。

我喜欢这种方法,因为我确保所有用户协议实例都将引用其各自的下层协议(Layer1Protocol 是例外,但它是核心库的一部分)。我认为这比使用指针更可取,因为一旦引入了指针,就可以传递空指针,然后可能需要在运行时进行检查,结果是大量的指针检查代码和偶尔的错误。

你认为我基于参考的方法可以辩护吗?还是使用空引用总是不好的做法?

IIRC 将引用绑定到 *nullptr 是安全的,只要从不访问引用。

不,取消引用nullptr始终是未定义的行为。在正确的程序中不能有"空引用"。

编写*static_cast<Protocol*>(nullptr)是取消引用nullptr,它调用未定义的行为。你永远不能那样做。结果可以是墨菲觉得的任何事情。这可能是你所说的"空引用",但也可能是你(男性,AFAIK)怀孕了,而程序就像你取消引用了一个有效的指针一样工作。

因此,严格来说,没有"空引用"。只是有未定义的行为

要么你的协议类总是不可避免地需要一个较低级别的协议,在这种情况下,你不能nullptr传递它(甚至不能伪装在引用中)。或者它不需要一直使用较低级别的协议,并且必须检查它是否有协议才能访问它,在这种情况下,指针可以更好地实现您的设计约束。

您的方法与使用指针的等效方法有何不同,除了语法之外,除了指针方法与引用方法不同,不调用 UB 的事实?

如果您正在使用引用以避免必须检查空指针,但随后传递(非法)空引用,那么您已经否定了引用的优势。现在,您的引用可能突然为 null,因此您可能需要检查该条件,就像使用指针一样。

如果,正如你所说,你可以保证这些空引用都不会被取消引用 - 好吧,如果你使用指针,同样的保证将成立。

长话短说:指针不是要不惜一切代价避免的。如果遇到可能发生空值的情况,则需要使用指针 -- 句点。您似乎担心必须在任何地方检查空指针(大概是通过断言),但在大多数体系结构上,MMU 无论如何都会阻止您取消引用空指针 - 这实际上几乎和断言一样好。

您可能想查看 boost 中的"可选"类模板(我相信)。它允许您传递对象,但也允许您指定您故意没有以比原始指针更安全的方式提供任何数据。

这不是我自己特别喜欢的东西,但你可能会发现它符合你的要求。