空 PTR 的运算符<<(流输出)

operator << (stream output) for nullptr

本文关键字:lt 输出 PTR 运算符      更新时间:2023-10-16

考虑一段通用C++代码,它向流输出其参数的值,以防它们不相等:

#define LOG_IF_NE(a, b) if(a != b) { 
    std::cerr << "Failed because (" << ##a << "=" << (a) << 
        ") != (" << ##b << "=" << (b) << ")"; 
}

这只是一个例子,实际代码在将消息写入字符串流后抛出异常。这对于定义了流operator <<的2个整数、2个指针等都很好。

int g_b;
int f(int a)
{
    LOG_IF_NE(a, g_b);
    // implementation follows
}

LOG_IF_NE的参数之一是nullptr时会出现问题:MSVC++2013编译器给出error C2593: 'operator <<' is ambiguous

int *pA;
int g()
{
    LOG_IF_NE(pA, nullptr);
}

出现此问题的原因是nullptr具有特殊类型,而STL中没有为该类型定义operator <<。答案在https://stackoverflow.com/a/21772973/1915854建议为std::nullptr_t 定义operator <<

//cerr is of type std::ostream, and nullptr is of type std::nullptr_t
std::ostream& operator << (std::ostream& os, std::nullptr_t)
{
    return os << "nullptr"; //whatever you want nullptr to show up as in the console
}

这是解决问题的正确方法吗?没有为nullptr_t定义operator<<,这不是C++11/STL中的一个错误吗?C++14/17中是否需要修复?或者这是故意的(因此,一个人对operator<<的私人定义可能会有缺陷)?

这是LWG#2221,它提出:

显而易见的库解决方案是添加一个nullptr_t过载,该过载将被定义为类似的东西

template<class C, class T>
basic_ostream<C, T>& operator<<(basic_ostream<C, T>& os, nullptr_t) 
{ 
  return os << (void*) nullptr; 
}

我们还可以考虑在核心级别上解决这个问题:添加一个特殊情况的语言规则,该规则可以解决所有编写f(nullptr)f在多个指针类型上重载的情况。(也许是决胜局说void*在这种情况下更可取。)

它不在C++14中,我不知道它是否会进入C++17。这是一个很容易自己解决的问题,所以就标准更改而言,这并不是特别重要的问题。正如你在问题中所说的,这只是一个3行函数。

我认为这可能是故意的,原因与nullptr本身的价值相同。在这种情况下默默地接受它可能被视为潜在的违反先决条件和不变量的行为。

nullptr是一个值,用于初始化指向的指针,以检测其是否尚未初始化。因此,按照这种逻辑,无论如何实际使用它都应该是明确的,并记录在案,以防止滥用和潜在的安全漏洞。简单地重载操作员打印出来无论如何都不会提供这种功能。

在调试环境中(宏将调用home),如果您要检查不变量和具有良好定义的输出的程序逻辑,则在条件编译中使用断言更有意义。

这基本上可以归结为一个设计点:在可以从中最好地恢复错误的地方处理错误。您的宏测试不等式,但如果它发现nullptr,则该宏处理该错误是没有意义的,因此重新进行异常处理更有意义,这样问题就可以被抛出到可以处理nullptr并从中恢复的地方。否则,您将允许程序处于不一致或不安全的状态。

编辑:刚刚看到您实际上在使用异常处理。嵌套的try/catch可能是最佳的,因为您可以在可以处理这两个错误的地方捕获它们。