我有一个像这样定义的函数:
void doSomethingWithCustomer (const Customer &customer);
我的一位开发人员称之为:
Customer *customer = order.getCustomer();
doSomethingWithCustomer (*customer);
不幸的是,如果订单没有绑定到客户,getCustomer
方法可以返回nullptr。
如果getCustomer
返回nullptr,那么应用程序在调用doSomethingWithCustomer
时不会崩溃,而是在使用客户引用的函数内崩溃。
当然,写这个的正确方法是首先检查客户不是nullptr,然后如果我们有一个有效的客户则调用该函数。 通常我们期望如果一个函数/方法有一个引用参数,那么调用者会检查它的有效性(这里不是这种情况),而不是函数本身检查参数。
我知道Visual Studio 2010(和早期版本)通过实际传递指针来传递引用,但我想知道这是否在C ++标准中的某处显示。我们可以假设引用始终作为指针传递(个人而言,我不会依赖于此,但知道这一点很有趣)?
是否有可能告诉Visual Studio在传递引用时,它应该首先自动取消引用它并在调用时崩溃而不是更深一些(在调试版本中执行此操作可能就足够了)?
答案 0 :(得分:4)
假设引用作为指针传递是否有效?
不,不是。
该标准并未强制要求以指针的形式实现引用。
如何实际实现引用是标准遗漏的实现细节,供实现决定。它仅描述了Reference中的预期行为,其中一个是标准符合程序中永远不能为NULL
的引用。
如果你的函数参数有时候应该是NULL
,那么你应该将它作为指针传递。
答案 1 :(得分:1)
没有。它是完全实现的定义。
出于诊断目的,我创建了一个验证参数的小容器类型。然后,您将声明函数/方法:
void doSomethingWithCustomer(const t_nonnull<const Customer>& pCustomer);
t_nonnull
类型在构造时验证参数。但是,我发现越来越频繁地使用引用更有用(IOW,在这种情况下不要返回指针 - 只是当客户不存在时才认为访问客户是错误的)。
答案 2 :(得分:1)
行为未定义。这意味着您不能依赖任何特定的方式来发现错误。一个好的编译器可能能够在编译时警告你,而另一个可能会完全掩盖错误,具体取决于你如何使用变量。您有责任确保引用永远不会为NULL。
答案 3 :(得分:1)
这是不可观察的,而且无关紧要。使用此代码的程序具有未定义的行为,因为它取消引用空指针。
答案 4 :(得分:0)
引用可能在内部使用指针实现(就像在Java中发生的那样)。但低于2的差异在他们之间至关重要:
类似地,T&
相当于T* const
。
您无需通知编译器有关引用变量的信息,因为这可能是您自己发生的。
void foo(T&);
T t, *p = 0;
foo(t); // the only way to pass reference
foo(*p); // the only way to pass reference
答案 5 :(得分:0)
正如其他人所说的那样,该标准没有强制如何实施参考。要尽早捕获“作为引用传递的dereferenced NULL”错误,您可以在函数内执行此操作:
void doSomethingWithCustomer (const Customer &customer)
{
assert(&customer);
//... rest of function
}