c – 为什么在通过const引用将未初始化的值传递给函数时g不报告警告?
作者:互联网
我正在查看给出in this earlier question的代码,其中包含的代码基本上如下:
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);
由于调用函数指针触发了警告但是将其传递给多图构造函数没有,我认为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会检测到直接使用未初始化的变量并尝试将未初始化的变量按值传递到函数中似乎非常不寻常,但是通过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(),无论是在调用doSomething()之前还是之后调用func.如果函数定义在不同的编译单元中,并且编译器警告这些事情,那么像上面这样的代码在某些情况下会给出虚假警告.
存在类似的技术,涉及将引用或指针存储为返回对象的成员的函数,该函数稍后将由调用者使用.如果这样的对象的构造函数使用传递的引用初始化const引用或指针,那么我在这里使用的const_cast将不是必需的.
对于开发人员来说使用这种技术是一个好主意是另一个故事 – 我当然认为上面的技术很差.但是使用这种技术的开发人员倾向于在他们关于“虚假”警告的抱怨中发声 – 包括在一些商业图书馆中 – 因此编译器供应商不愿发出警告.
标签:c,initialization,g,compiler-warnings 来源: https://codeday.me/bug/20190829/1757332.html