如代码所示,get_string函数内部声明了2个遍历,但是它们的地址不是相邻的,因为get_string把String返回了。而no_get_string内部的两个变量地址是相邻的。这有什么优化吗?
fn main() {
let s1 = get_string();
println!("in main s:{:p}", &s1);
no_get_string();
}
#[inline(never)]
fn get_string() -> String {
let a = 1;
let s = "a".into();
println!("in get_string a: {:p}", &a);
println!("in get_string s: {:p}", &s);
println!(
"in get_string s - a: {}",
&s as *const String as usize - &a as *const i32 as usize
);
s
}
#[inline(never)]
fn no_get_string() {
let a = 1;
let s = "a".into();
println!("in no_get_string a: {:p}", &a);
println!("in no_get_string s: {:p}", &s);
println!(
"in get_string s - a: {}",
&s as *const String as usize - &a as *const i32 as usize
);
}
运行结果:
in get_string a: 0x7ffee6a82a1c
in get_string s: 0x7ffee6a82b28
in get_string s - a: 268
in main s:0x7ffee6a82b28
in no_get_string a: 0x7ffee6a82a04
in no_get_string s: 0x7ffee6a82a08
in get_string s - a: 4
可以看到main中打印字符串的地址和get_string函数打印字符串地址相同,且函数中字符串和数字a的地址并不相邻。 而no_get_string中字符串地址和a的地址相邻。
1
共 6 条评论, 1 页
评论区
写评论主要是我又在看pin相关的内容了。以前通过函数返回一个自引用结构体,能模拟出问题,昨晚发现不能模拟了,一看原来返回的自引用结构体的地址不是在函数的栈中。
--
👇
guobbs: 原来也有老铁跟我一样,爱搞清楚底层的旯旯旮旮。
我最早开始是从VC++6.0学习C++,那个时候的学习理论返回的对象是函数栈中的一个副本,如果自定义对象很大,复制开销也很大,一般是不推荐这样设计接口获取返回值,经典的搞法是给接口函数传递对象指针,来获取返回结果。
但是这个理论到了C++11出现了颠覆,发现有很多接口又开始通过返回值来返回对象了,我对这个非常敏感,于是好奇做了大量实验,通过反汇编查看了一下代码实现,调用这样的接口都是在调用方的栈帧空间分配要接收结果的对象,接口内部能直接拿到调用方分配的对象地址,一下子明白了,上面的老兄提到 @viruscamp RVO(返回值优化)指的就是这个,网上有介绍说C++11中对比已经有了规定。这种方式对编程写代码非常友好。
刚接触到rust的时候,也是大量这样的写法(直接返回结果对象),每看一次都觉得不影响性能么(别扭)?后面也是通过反汇编查看,才释然了。
结合上面描述,回到楼主这个话题,就容易理解为什么 get_string()中s1的地址与 main 中 s 的地址是一样的了。
原来也有老铁跟我一样,爱搞清楚底层的旯旯旮旮。
我最早开始是从VC++6.0学习C++,那个时候的学习理论返回的对象是函数栈中的一个副本,如果自定义对象很大,复制开销也很大,一般是不推荐这样设计接口获取返回值,经典的搞法是给接口函数传递对象指针,来获取返回结果。
但是这个理论到了C++11出现了颠覆,发现有很多接口又开始通过返回值来返回对象了,我对这个非常敏感,于是好奇做了大量实验,通过反汇编查看了一下代码实现,调用这样的接口都是在调用方的栈帧空间分配要接收结果的对象,接口内部能直接拿到调用方分配的对象地址,一下子明白了,上面的老兄提到 @viruscamp RVO(返回值优化)指的就是这个,网上有介绍说C++11中对比已经有了规定。这种方式对编程写代码非常友好。
刚接触到rust的时候,也是大量这样的写法(直接返回结果对象),每看一次都觉得不影响性能么(别扭)?后面也是通过反汇编查看,才释然了。
结合上面描述,回到楼主这个话题,就容易理解为什么 get_string()中s1的地址与 main 中 s 的地址是一样的了。
返回值优化, RVO,相关文章 C++的比较多,但用在rust一样的。
生命周期 应该是区分String生命周期
大佬,代码贴了
--
👇
viruscamp: 别直接贴 play.rust-lang.org 的地址,先 Share, 最好把代码直接贴一遍。
别直接贴 play.rust-lang.org 的地址,先 Share, 最好把代码直接贴一遍。