为什么 g++ 在通过 const 引用将未初始化的值传递给函数时不报告警告?

Why doesn't g++ report warnings when passing uninitalized values into functions by const reference?

我正在查看给定的代码 ,其中包含的代码基本上如下:

bool (*uninitializedFunctionPointer)(int, int);
typedef std::multimap<int, std::string, bool(*)(int, int)> MultiMapType;
MultiMapType myMap(uninitializedFunctionPointer);

请注意(顾名思义)uninitializedFunctionPointer 是传递给 myMap 的构造函数的未初始化函数指针。奇怪的是,当我用带-Wall -Werror的g++ 4.8.4编译这段代码时,它编译这段代码时没有报告任何警告。但是,它确实报告了类似代码的错误:

bool (*uninitializedFunctionPointer)(int, int);
uninitializedFunctionPointer(137, 42);

由于调用函数指针触发了警告但将其传递给 multimap 构造函数却没有,我认为 g++ 只是不关心将未初始化的值作为参数传递给函数。但是,此代码确实会触发警告:

void doSomething(bool (*function)(int, int)) {
    function(137, 42); // Problem if 'function' is uninitialized
}

bool (*uninitializedFunctionPointer)(int, int);
doSomething(uninitializedFunctionPointer); // Warning!

我去了 cppreference documentation for multimap 并看到 multimap 构造函数通过 const 引用接收其比较器,所以我尝试编写以下代码:

typedef bool (*FunctionType)(int, int);
void doSomething(const FunctionType &function) {
    function(137, 42); // Problem if 'function' is uninitialized
}

bool (*uninitializedFunctionPointer)(int, int);
doSomething(uninitializedFunctionPointer);

而且,令人惊讶的是,这段代码编译完全没有任何警告。我认为这可能与函数指针有关,但看起来并非如此!这是仅使用普通旧整数的相关代码:

void doSomething(const int &value) {
    std::cout << value << std::endl; // Problem if value is uninitialized
}

int uninitializedInt;
doSomething(uninitializedInt);

即使启用 -Wall,此代码编译时也没有任何警告。

我知道编译器不需要针对所有类型的编程错误发出警告,但 g++ 检测到直接使用未初始化变量并试图将未初始化变量传递到按值函数,但在将未初始化的变量传递给函数时不会报告问题 by const reference。

g++ 不会在此处报告警告是否有令人信服的理由?比如,是否有合理的代码可以通过 const 引用将未初始化的变量传递给函数而不触发某种未定义的行为?或者这只是编译器的疏忽?

出现问题是因为给定一个引用,函数可能存储一个指针或引用。

typedef bool (*FunctionType)(int, int);

FunctionType *stored_function;

void doSomething(const FunctionType &function)
{
     stored_function = const_cast<FunctionType *>(&function);
}

void doSomethingElse(int a, int b)
{
     (*stored_function)(a, b);
}

bool a_function(int, int)
{
    // do something
    return false;
}


int main()
{
    FunctionType func;
    doSomething(func);

    func = a_function;

    doSomethingElse(1,2);
}

这将导致 doSomethingElse() 调用 a_function(),无论对 func 的赋值发生在 doSomething() 的调用之前还是之后。如果函数定义在不同的编译单元中,并且编译器会发出警告,在某些情况下,像上面这样的代码会给出虚假警告。

还有一些类似的技术涉及函数将引用或指针存储为返回对象的成员,稍后将由调用者使用。如果此类对象的构造函数使用传递的引用初始化 const 引用或指针,则不需要我在此处使用的 const_cast

开发人员使用此类技术是否是个好主意是另一回事 - 我当然认为以上是糟糕的技术。但是使用此类技术的开发人员往往会直言不讳地抱怨 "spurious" 警告 - 包括在某些商业库中 - 因此编译器供应商宁愿不发出警告。