考虑这个代码片段
#include <iostream>
int foo() {
int a;
return a;
}
int main() {
auto &&ret = std::move(foo());
std::cout << ret;
}
Run Code Online (Sandbox Code Playgroud)
使用ASAN编译g++ -fsanitize=address -fno-omit-frame-pointer -g -std=c++17 main.cpp -o main,运行./main显示错误
==57382==ERROR: AddressSanitizer: stack-use-after-scope on address 0x00016b3cb480 at pc 0x000104a37e68 bp 0x00016b3cb450 sp 0x00016b3cb448
READ of size 4 at 0x00016b3cb480 thread T0
#0 0x104a37e64 in main main.cpp:8
#1 0x104a75084 in start+0x200 (dyld:arm64e+0x5084)
Run Code Online (Sandbox Code Playgroud)
但是如果我在 auto 之后删除引用,这段代码可以编译并运行,而不会出现 ASAN 给出的错误。我不明白的是,如果std::move返回对给定对象的引用,那么该对象(foo()在本例中是临时创建的)将在函数调用返回后被销毁std::move,因此无论它是绑定到右值引用还是分配给新值应该无效,因为该临时值在移动操作后已经被销毁,对吗?那么为什么 ASAN 在第二种情况下不会给出错误。
- - - - - - - - - - -更新 - - - - - - - -
#include <iostream>
int foo() {
int a = 1;
return a;
}
int main() {
auto &&ret = std::move(foo());
std::cout << ret;
}
Run Code Online (Sandbox Code Playgroud)
a如果我不使用 ASAN 进行编译,此代码实际上将运行而不会出现错误,它不会触发分段错误或任何内容,并打印 1 ,这与函数中的相同foo。从下面的答案中我了解到临时被销毁了,对auto &&ret = std::move(foo());吧?这是未定义的行为吗?
临时的仅在完整表达后才被销毁。(初始化后ret)
// 1. the temporary is created and bind to std::move parameter
// 2. std::move return reference to the temporary
// 3. it's *value* copied to ret
// 4. temporary is destoryed, but it'd not effect the copy (`ret`)
auto ret = std::move(foo());
Run Code Online (Sandbox Code Playgroud)
// 1. the temporary is created and bind to std::move parameter
// 2. std::move return reference to the temporary
// 3. the *reference* is set to `ret`
// 4. temporary is destoryed, `ret` now contains dangling reference
auto&& ret = std::move(foo());
Run Code Online (Sandbox Code Playgroud)