我看到了许多其他关于同一警告的问题,但我的代码似乎不同。
而且,总的来说,我只能通过 -Os 选项才能得到这个。
#include <iostream>
using namespace std ;
template <class TYPE,class FUNC> struct AutoDestruct
{
const TYPE & var ;
FUNC func ;
AutoDestruct ( const TYPE & v , FUNC f ) : var(v),func(f) {}
~AutoDestruct () { func(var) ;}
};
class Dictionary
{
public:
Dictionary & wipe () { cout << "Dictionary.wipe()\n" ; return *this ;}
};
static void wipe_dict ( Dictionary * dict ) { dict->wipe() ;}
typedef AutoDestruct<Dictionary*,void(*)(Dictionary*)> AutoWipe ;
int main ()
{
cout << "enter main function " << __DATE__ << " " << __TIME__ << endl ;
Dictionary headers ;
AutoWipe auto_wipe( &headers,wipe_dict ) ;
cout << "exit main function\n" ;
}
命令行是:
g++ -std=c++11 -Os -Wall -Wextra test.cpp && ./a.out
输出是:
test.cpp: In function ‘int main()’:
test.cpp:9:48: warning: ‘<anonymous>’ may be used uninitialized [-Wmaybe-uninitialized]
9 | ~AutoDestruct () { func(var) ;}
| ^~~~
test.cpp:25:46: note: ‘<anonymous>’ was declared here
25 | AutoWipe auto_wipe( &headers,wipe_dict ) ;
| ^
enter main function May 13 2024 20:14:01
exit main function
Dictionary.wipe()
编译器是:
g++ (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
这是我真实代码的一个非常简单的摘录,只是为了暴露警告。
但请注意,在我的真实代码中,执行 auto_wipe 时,我收到警告 AND 段错误!
知道警告+段错误原因吗? 预先感谢!
我认为走一小段路是值得的,因为我想我不是唯一一个最初误读你的代码的人。我认为我正在阅读的代码是这样的:
#include <iostream>
using namespace std;
template <class TYPE,class FUNC> struct AutoDestruct {
TYPE& var ;
FUNC func ;
AutoDestruct(TYPE& v, FUNC f ) : var(v),func(f) {}
~AutoDestruct () { func(var) ;}
};
struct Dictionary {
Dictionary & wipe () { cout << "Dictionary.wipe()\n" ; return *this ;}
};
static void wipe_dict ( Dictionary & dict ) { dict.wipe() ;}
typedef AutoDestruct<Dictionary,void(*)(Dictionary&)> AutoWipe ;
int main () {
Dictionary headers ;
AutoWipe auto_wipe( headers,wipe_dict) ;
}
auto_wipe
存储对 headers
的引用,当调用它的析构函数时,它会调用 headers.wipe();
。然后调用 headers
析构函数,一切都很好。
虽然在你的代码中,这里:
AutoWipe auto_wipe( &headers,wipe_dict ) ;
您的
auto_wipe
存储对临时 &headers
的引用。当 auto_wipe
的析构函数被调用时,对象 headers
当然仍然存储在相同的内存地址中。然而,由 &headers
产生的临时指针早已消失,并且该成员是一个悬空引用。您可以按照注释中的建议复制指针,也可以按照上面的方式存储对实际对象的引用。
TL;DR:编译器发出警告是正确的。您存储一个悬空引用。使用地址消毒剂会突出这个问题。