此代码具有未定义的行为:
#include <string>
std::string make_str(const char* s)
{
return s;
}
const char* get_str(const std::string& s)
{
return s.c_str();
}
const char* bad()
{
return get_str(make_str("hello"));
}
错误的函数会创建一个临时的std :: string并返回一个指向其数据的指针,该函数返回后将立即失效。
GCC 5+会捕获此错误(“函数返回本地变量的地址”),但仅当使用-O3
进行编译时才可以。在包括-O2
在内的更典型的优化级别上,即使使用-Wall -Wextra
,GCC也会毫无抱怨地对其进行编译。除非您使用实验性的-Wlifetime
功能,否则Clang永远不会捕获它。
我的问题是:我们能否明确告知编译器此类生命周期依赖性,例如使用属性?例如,我希望能够做到这一点:
[[lifetime-depends : s]] // hypothetical syntax
const char* get_str(const std::string& s);
或者也许是这样
const char* get_str(const std::string& s)
__attribute__((lifetime-depends(0))); // hypothetical syntax
我会接受一个适用于GCC或Clang的任何正式版本的答案,但更喜欢带有C ++ 14的GCC 6.1。 Clang的实验性-Wlifetime
并不是答案,因为我想明确一点,而不是依靠启发法(看来启发法无论如何都无法在多个翻译单元中工作)。
或者,我将接受一个答案,其中提供了为什么这样做无效或不可行的原因。
答案 0 :(得分:4)
恕我直言,这将意味着在编译器智能方面非常可靠,可以捕获用户错误,因为那是您发布的代码,是失败的。该标准已经涵盖了如何处理临时人员的寿命,并且确实考虑在参考仍在使用的情况下延长寿命(请参见n4713草案,例如15.2项目符号5)。但是,您发布的示例是另一种情况...
此外,尽管论文p1179r0(P.W评论)确实提出了指向存储在堆栈上的对象的指针的想法,但它对堆上的对象没有帮助。怎么办?返回指向char(或任何类型)的指针不是错误...返回指向不再存在的数组的指针是。怎么知道c_str()返回一个指向在其中的析构函数中删除的临时wich数组的指针(特定于Kinda,不是吗?)?如何知道阵列是否被破坏?通过查看析构函数是否完成删除?如果析构函数不删除怎么办?警告析构函数应删除?如果new
是新的展示位置怎么办?如果...工厂模式怎么办?如果为智能指针创建指针(例如:shared_ptr)呢?如果再增加200点呢?在堆上管理生存期,通常会导致垃圾回收。
您收到的警告是function returns address of local variable [-Wreturn-local-addr]
,我认为这与您的代码无关,但更多是由短字符串优化引起的“意外”。经过SSO优化的std::string
确实将消息返回指向本地的指针...简单测试,使您的字符串长度超过16个字符,警告disappears ... < / p>