我正在查看给定in this earlier question的代码,其中包含的代码基本上如下:
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 ++会检测到直接使用未初始化的变量并尝试将未初始化的变量传递给按值运行,但在通过const引用将未初始化的变量传递给函数时不会报告问题。
有没有令人信服的理由说明为什么g ++不会在这里报告警告?在中,是否存在合理的代码,其中未初始化的变量可以通过const引用传递给函数而不会触发某种未定义的行为?或者这只是编译器的疏忽?
答案 0 :(得分:5)
问题出现了,因为给定引用,函数可以存储指针或引用。
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
I。
开发人员使用这种技术是否一个好主意是另一个故事 - 我当然认为上面的技术很差。但是,使用这种技术的开发人员倾向于在他们关于&#34;虚假&#34;警告 - 包括在一些商业图书馆中 - 因此编译器供应商不愿发出警告。