#include <stdio.h>
#include <array>
#include <vector>
std::vector<int> foo() {
int i;
std::vector<int> a(100);
printf("%p, %p, %p\n", &i, &a, &(a[0]));
return a;
}
int main() {
int i;
std::vector<int> b = foo();
printf("%p, %p, %p\n", &i, &b, &(b[0]));
}
Run Code Online (Sandbox Code Playgroud)
为什么a和上面b有相同的地址?这是某种“跨堆栈框架”优化吗?即使我使用该-O0选项,结果也是一样的。
输出:
$ vim main.cpp
$ cc -std=c++11 -lc++ main.cpp
$ ./a.out
0x7ffee28d28ac, 0x7ffee28d28f0, 0x7ff401402c00
0x7ffee28d290c, 0x7ffee28d28f0, 0x7ff401402c00
$
Run Code Online (Sandbox Code Playgroud)
Wer*_*nze 57
这是因为复制省略/命名返回值优化 (NRVO)。foo返回一个命名对象a。所以编译器不是创建本地对象并返回它的副本,而是在调用者放置它的地方创建对象。您可以在https://en.cppreference.com/w/cpp/language/copy_elision上阅读更多相关信息。虽然自 C++17 起 RVO 是强制性的,但 NRVO 不是,但看起来您的编译器即使在-O0.
正如其他人所解释的,这是因为复制 elison。您可以通过以下方式使用 g++ 禁用它:
g++ -fno-elide-constructors main.cpp
Run Code Online (Sandbox Code Playgroud)
其中main.cpp包含您的代码。
现在a和b有不同的地址,但由于移动语义a[0],b[0]将有相同的地址。