返回std ::领带 - 悬挂参考?
关于从功能返回STD :: TIE的问题。如果我正确理解,那么STD :: TIE只包含参考。因此,返回一个std ::指向功能 - 本地变量的tie是一个非常糟糕的主意。编译器不应该检测到这一点并发出警告吗?
实际上,我们在代码中遇到了此错误,并且所有的编译器和消毒器都没有检测到它。令我感到困惑的是,任何工具都没有报告。还是我不正确地理解了什么?
#include <tuple>
struct s_t {
int a;
};
int& foo(s_t s) {
return s.a; // warning: reference to local variable 's' returned
}
int& bar(s_t &s) {
return s.a; // ok
}
auto bad(s_t s) {
return std::tie(s.a); // no warning
}
auto fine(s_t &s) {
return std::tie(s.a); // no warning
}
int main() {
s_t s1,s2;
auto bad_references = bad(s1);
auto good_references = fine(s2);
// ...
return 0;
}
Question on returning std::tie from a function. If I understand correctly, then std::tie only contains references. So, returning a std::tie which points to function-local variables is a very bad idea. Shouldn't the compiler be able to detect this and issue a warning ?
Actually, we had this error in our code and all compilers and sanitizers we have missed to detect it. I was quite puzzled that this didn't get reported by any tool. Or do I understand anything incorrectly?
#include <tuple>
struct s_t {
int a;
};
int& foo(s_t s) {
return s.a; // warning: reference to local variable 's' returned
}
int& bar(s_t &s) {
return s.a; // ok
}
auto bad(s_t s) {
return std::tie(s.a); // no warning
}
auto fine(s_t &s) {
return std::tie(s.a); // no warning
}
int main() {
s_t s1,s2;
auto bad_references = bad(s1);
auto good_references = fine(s2);
// ...
return 0;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您对终身行为的理解是正确的。
std :: tie
仅存储引用,并且您必须确保在引用对象被破坏后不使用它们。在函数调用的末尾或包含功能调用的全表达末尾(实现定义)在函数调用末尾或在全表达结束时被销毁。因此,使用存储在bad_references
中的引用将导致不确定的行为。您可能只会从编译器警告功能和Linter功能中期望过多。他们通常不会对代码进行广泛的分析。这里的分析需要通过多个功能调用层,成员的商店以及功能的返回来跟踪参考。如此复杂的分析是静态分析仪的目的。
但是,从版本12.1 GCC开始似乎使用了插入函数调用的结果来报告使用
-O2 -WALL -WALL -WEXTRA
:我没有设法获得当前的Clang和MSVC来产生诊断,但是。我想这也适用于GCC,只要所有相关函数呼叫都被归类。使用EG
-O0
未产生GCC警告,如果之间存在更复杂的功能调用层,则可能不会产生它。Clang-Analyzer报告的静态分析仪
请参见 https://godbolt.org.org/z/ze/ze8px8vt9
有叮当的中继和优化禁用的ASAN还报告了问题:
请参见 https://godbolt.org/z/eo7cweam 。
可能的内部可能会使消毒剂更难检测到这一点。他们可能不会在内联之前添加支票。
Your understanding of the lifetime behavior is correct.
std::tie
stores only references and you must assure that they are not used after the referenced object is destroyed. By-value function parameters are destroyed either at the end of the function call or at the end of the full-expression containing the function call (implementation-defined). So using the references stored inbad_references
will cause undefined behavior.You might just be expecting too much from the compiler warning features and linter features. They generally don't do extensive analysis of the code. The analysis here would need to keep track of the reference through multiple function call layers, a store to a member and the return from the function. Such more complex analysis is what a static analyzer is for.
However, starting with version 12.1 GCC seems to use the result of inlining function calls to report with
-O2 -Wall -Wextra
:I didn't manage to get current Clang and MSVC to produce a diagnostic, though. I guess this will work for GCC also only as long as all the relevant function calls are inlined. With e.g.
-O0
the GCC warning is not produced and it probably won't be produced either if there are more complex function call layers inbetween.A static analyzer like clang-analyzer reports
See https://godbolt.org/z/zE8Px8vT9 for both.
With Clang trunk and optimizations disabled ASAN also reports the problem:
See https://godbolt.org/z/eYo7cWeaM.
Probably the inlining makes it harder for the sanitizers to detect this. They probably don't add the checks prior to inlining.
您应该知道自我提出的问题是RAII(资源获取是初始化 - 有人说这是C ++中最重要的事情)
在您的示例中:
foo(s_t s);
将通过复制构造器初始化s
。当foo退出时,s
将被销毁,以便sa
引用悬挂对象bar(s_t&amp; s)
是可以的&amp; s 是参考存在的变量(通常)以上函数调用bad(s_t s)
fine(s_t&amp; s)
是可以的是返回值而不是引用/指针到本地变量What you should know to self-answer this question is RAII (resource acquisition is initialization- Some one say it is the most importance thing needed to know in C++)
In your example:
foo(s_t s);
will initializes
via copy constructor. When foo exit,s
will be destroyed so thats.a
referencing to a dangling objectbar(s_t &s)
is ok because&s
is reference to existed variable (that usually) outlive the function callbad(s_t s)
fine(s_t &s)
is ok because it is return value not reference/pointer to local variable