- 主题:这个右值引用返回有问题? 为什么一运行就segmentation fault?
好的, 谢谢您的回答
【 在 Bernstein 的大作中提到: 】
: 不需要,不会复制
: 返回值优化很久以前就有了
:
--
FROM 106.120.11.*
您好, 谢谢您的回答.
您的回答中提到, 只有把这个右值引用传给一个移动构造、移动赋值函数时,才会发生数据转移。
我是这样想的, 在get_cmp_files这个子函数中, 返回vector&&, 在主函数中用auto v = get_cmp_files("cmp");中的v变量接住, 我理解这时候会调用vector的移动构造函数, 从而让v的堆直接指向get_cmp_files函数中的res堆, 避免值语义的复制构造.
【 在 z16166 的大作中提到: 】
: 1、返回的右值引用也好,引用也好,都是指向函数内部的栈上临时变量的,都是use-after-free的错误。
: 所以不能返回栈上临时变量的引用、右值引用。
: 2、返回栈上的临时变量时,用值返回就行,编译器会有自动的RVO优化。而且不要加std::move,加了反而会影响RVO。
: ...................
--
FROM 106.120.11.*
不会。
auto v = get_cmp_files("cmp");
等价于
std::vector<std::string> && v = get_cmp_files("cmp");
v是个引用,不是个值类型的变量,不会调用任何构造。
如果写成
std::vector<std::string> v = get_cmp_files("cmp");
就会调用std::vector的move构造,但是move的是栈上已经销毁的变量,还是会崩
所以这个问题就是不能引用某个函数内的栈上的临时变量,不能返回这个变量的引用、右值引用、指针等拿来用。
不想复制大量数据,改函数定义,用常规搞法:
std::vector<std::string> get_cmp_files(const std::string& dir);
void get_cmp_files(const std::string& dir, std::vector<std::string> &files);
bool get_cmp_files(const std::string& dir, std::vector<std::string> &files);
【 在 hl0737 的大作中提到: 】
: 您好, 谢谢您的回答.
: 您的回答中提到, 只有把这个右值引用传给一个移动构造、移动赋值函数时,才会发生数据转移。
: 我是这样想的, 在get_cmp_files这个子函数中, 返回vector&&, 在主函数中用auto v = get_cmp_files("cmp");中的v变量接住, 我理解这时候会调用vector的移动构造函数, 从而让v的堆直接指向get_cmp_files函数中的res堆, 避免值语义的复制构造.
: ...................
--
修改:z16166 FROM 123.118.191.*
FROM 123.118.191.*
g++ -Wall会有警告
gcc 8.3.0没警告,12.x有警告
happy@UOS-128G:~$ /opt/cross/bin/x86_64-linux-musl-g++ -static -Wall 1.cpp
1.cpp: In function ‘std::vector<std::__cxx11::basic_string<char> >&& get_cmp_files(const std::string&)’:
1.cpp:22:22: warning: reference to local variable ‘res’ returned [-Wreturn-local-addr]
22 | return std::move(res);
| ~~~~~~~~~^~~~~
1.cpp:9:31: note: declared here
9 | std::vector<std::string> res;
| ^~~
【 在 hl0737 的大作中提到: 】
: std::vector<std::string>&& get_cmp_files(const std::string& dir) {
: std::vector<std::string> res;
: DIR* dp;
: ...................
--
FROM 123.118.191.*
我觉得,右值引用只是延长了右值的生命期,但还没有到改变作用域的地步。
更何况move也不能修改对应左值的作用域。
【 在 hl0737 的大作中提到: 】
: std::vector<std::string>&& get_cmp_files(const std::string& dir) {
: std::vector<std::string> res;
: DIR* dp;
: ...................
--来自微微水木3.5.14
--
修改:foliver FROM 39.144.104.*
FROM 39.144.104.*
好的,非常感谢您的回答,但是还有一点点小疑问想请教一下您。
vector中的数据是存储在堆上的, 也就是动态创建的一块内存,vector中有一个指针指向这块内存
如get_cmp_files中的vector res,假设res中指向堆的指针为p_sub, 这块内存是buffer S
如果我在main函数中用vector<string> v = get_cmp_files(xx) 接住它,这时候会调用vector的移动构造函数,假设v中指向堆的指针为p_main, 最开始为nullptr,那么此时我认为会交换两个指针的值,即p_main指向buffer S,p_sub指向nullptr,然后get_cmp_files函数结束,vector res析构,此时res发现p_sub指向nullptr,因此不会析构任何一块内存,所以虽然vector res定义在子函数中,但是通过移动构造,它的内存成功返回到了main函数中,没有被销毁
我理解这也是移动构造创造出来的意义,上面的这段理解在C++中会有什么问题嘛?
【 在 z16166 的大作中提到: 】
: 不会。
: auto v = get_cmp_files("cmp");
: 等价于
: ...................
--
FROM 219.142.184.*
理解不对
1、res是在函数返回之前已经被析构,其占用的堆内存释放了,占用的栈内存可能被覆盖/复用了。
一个已经无意义的变量res,其别名(左值引用、右值引用)、指针也等价于立即无效了,没有机会被函数外面的代码再来move走其内部的数据。
强行move,可以认为是UB
2、move构造不是"交换"两个对象内部的数据,是单向的。
【 在 hl0737 的大作中提到: 】
: 好的,非常感谢您的回答,但是还有一点点小疑问想请教一下您。
: vector中的数据是存储在堆上的, 也就是动态创建的一块内存,vector中有一个指针指向这块内存
: 如get_cmp_files中的vector res,假设res中指向堆的指针为p_sub, 这块内存是buffer S
: ...................
--
修改:z16166 FROM 123.118.191.*
FROM 123.118.191.*
好的,明白了,特别感谢您的耐心回答,谢谢!
【 在 z16166 的大作中提到: 】
: 理解不对
: 1、res是在函数返回之前已经被析构,其占用的堆内存释放了,占用的栈内存可能被覆盖/复用了。
: 一个已经无意义的变量res,其别名(左值引用、右值引用)、指针也等价于立即无效了,没有机会被函数外面的代码再来move走其内部的数据。
: ...................
--
FROM 219.142.184.*
【 在 hl0737 的大作中提到: 】
: 好的,非常感谢您的回答,但是还有一点点小疑问想请教一下您。
: vector中的数据是存储在堆上的, 也就是动态创建的一块内存,vector中有一个指针指向这块内存
: 如get_cmp_files中的vector res,假设res中指向堆的指针为p_sub, 这块内存是buffer S
: ...................
这个理解是右值使用场景, 但不是发生在std::move 或 std::forward的调用,
这两个函数, 实际作用只是类型转换, 实际就是符号的语义解释在语言层面发生了变化,
并没有引起内存位置形态的变化, 你说的那些东西, 实际上,
是发生在移动拷贝构造过程。
另外, 你要理解 , 右值是值, 右值引用也不过是值引用,
而值的存在有多种多样, 场景的常量可以编码到机器代码里, 可以存在于常量数据区,
也可以存在于静态数据段, 堆上, 或者栈上。
而右值引用的存在只保证是这些内存地址资源的别名, 而无法锁定或者延长它们的生存期。
std::vector<std::string>&& get_cmp_files(const std::string& dir)
这个函数定义, 包括return中的move, 都只是让函数返回了一个右值引用,
这个右值实际引用的地址确实函数局部变量, 也就是函数局部的栈内存, 它的生存期在函数返回
就已经消亡了。
auto v = get_cmp_files("vvv");
这一句, 这个右值引用其实已经指向了失效内存。
合理的做法, 其实就是返回值就行
std::vector<std::string> get_cmp_files(const std::string& dir)
这个时候, 实际上return会生成临时对象, 发生右值引用向左值赋值导致的移动拷贝。
std::vector<std::string>& v = get_cmp_files("vvv");
我觉得这样接收(引用)这个对象就是可以的。
--
FROM 124.126.0.*
好的, 谢谢您的耐心回答, 非常感谢!
【 在 poggy 的大作中提到: 】
:
: 这个理解是右值使用场景, 但不是发生在std::move 或 std::forward的调用,
: 这两个函数, 实际作用只是类型转换, 实际就是符号的语义解释在语言层面发生了变化,
: ...................
--
FROM 36.112.91.*