我的同事最近在Windows中编译了我们的程序,发现了一个类似的错误:
std::string a = "hello ";
std::string b = "world";
const char *p = (a+b).c_str();
printf("%s\n", p);
由于某种原因,我们的Linux可执行文件没有崩溃。
我们的编译器都没有发出任何警告,所以我们现在担心代码中可能存在此错误。
虽然我们可以 grep c_str()
次出现并进行目视检查,但有可能还有人做过以下事情:
struct I {
int num;
I() { num=0; }
};
struct X {
I *m;
X() { m = new I; }
~X() { delete m; }
I get() { return *m; } // version 1, or
I& get() { return *m; } // version 2
};
并按以下方式访问:
I& a = X().get(); // will get a reference to a temporary, or a valid copy?
cout << a.num;
而不是:
cout << X().get().num;
这是安全的(不是吗?)
问题:有没有办法可以捕获这些错误(可能使用编译器,甚至是断言)?
我需要确保如果struct X
的作者在版本1 和 2 之间更改get()
,程序将发出错误警告
答案 0 :(得分:2)
简单回答:一般来说,你无法捕获这些错误,原因是有类似的结构可能完全正常,因此编译器必须知道所有函数的语义才能警告你。
在更简单的情况下,就像获取临时地址一样,许多编译器已经警告过你,但在一般情况下,编译器知道它是非常困难的。
对于.c_str()
的一些类似示例,请考虑:
std::vector< const char * > v;
v.push_back( "Hi" );
const char* p = *v.begin();
对begin
的调用返回一个临时的,类似于表达式(a+b)
,并且您正在调用返回operator*
的临时(const char*
)的成员函数,这与您的原始案例非常相似(从涉及的类型的角度来看)。问题是,在这种情况下,指针对象在调用之后仍然有效,而在你的(.c_str()
)它不是,但它是操作语义的一部分,而不是编译器可以检查的语法为了你。对于.get()
示例也是如此,编译器不知道返回的引用是否是在表达式之后有效的对象。
所有这些属于未定义行为类别。
答案 1 :(得分:1)
查看此问题的解决方案,我认为它与您正在寻找的内容类似:
C++ catching dangling reference
有基于运行时的解决方案可以检测代码 无效的指针访问。到目前为止我只使用过mudflap(这是 从版本4.0开始集成在GCC中)。 mudflap试图追踪每一个 代码中的指针(和引用),如果是则检查每次访问 指针/引用实际上指向其基类型的活动对象。 这是一个例子:{...}