如何检测对临时对象成员的引用

how to detect references to members of temporary objects

本文关键字:临时对象 成员 引用 何检测 检测      更新时间:2023-10-16

我的同事最近在Windows上编译我们的程序,发现了一个类似的错误:

  std::string a = "hello "; 
  std::string b = "world"; 
  const char *p = (a+b).c_str();
  printf("%sn", 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的作者在版本12之间更改get(),程序将警告错误

简单的回答:一般来说,您无法捕获这些错误,原因是存在类似的结构,这些结构可能完全没有问题,因此编译器必须知道所有函数的语义才能向您发出警告。

在更简单的情况下,比如获取临时地址,许多编译器已经警告你了,但在一般情况下,编译器很难知道,如果不是不可能的话。

对于.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()的例子也是如此,编译器不知道返回的引用是否指向一个在表达式之后有效的对象。

看看这个问题的解决方案,我认为它做了一些类似于你正在寻找的东西:

c++捕获悬空引用

有基于运行时的解决方案来检测代码无效的指针访问。到目前为止,我只使用过挡泥板(这是从4.0版开始集成在GCC中)。泥板试图追踪每一个指针(和引用),并检查每次访问是否指针/引用实际上指向其基类型的活动对象。下面是一个例子:{…}