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

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

本文关键字:函数 值传 警告 报告 g++ const 引用 为什么      更新时间:2023-10-16

我正在查看前面的问题中给出的代码,其中包括基本上如下的代码:

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

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

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 文档以获取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++ 会检测到直接使用未初始化的变量并尝试按值将未初始化的变量传递到函数中,但在通过 const 引用将未初始化的变量传递到函数中时不会报告问题。

是否有令人信服的理由说明 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

开发人员使用这种技术是否是一个好主意是另一回事 - 我当然认为上述技术很差。 但是使用这种技术的开发人员往往会抱怨"虚假"警告 - 包括一些商业库 - 因此编译器供应商宁愿不发出警告。