- 主题:这个右值引用返回有问题? 为什么一运行就segmentation fault?
1、返回的右值引用也好,引用也好,都是指向函数内部的栈上临时变量的,都是use-after-free的错误。
所以不能返回栈上临时变量的引用、右值引用。
2、返回栈上的临时变量时,用值返回就行,编译器会有自动的RVO优化。而且不要加std::move,加了反而会影响RVO。
std::move()是个很大的障眼法,很多人以为它会自动转移class/struct内部的数据。
如果你以为std::move会把栈上临时变量的值转移到你的main()里的那个变量v里边,这是错误的。
它只是强制把引用转为右值引用,但本质还是个引用。只有把这个右值引用传给一个移动构造、移动赋值函数时,才会发生数据转移。
【 在 hl0737 的大作中提到: 】
: 额, 我想的是不要vector值复制...如果直接返回左值, vector的内容不是会复制一份么
--
修改:z16166 FROM 123.118.191.*
FROM 123.118.191.*
不会。
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.*
理解不对
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.*
此处不需要std::move,让编译器自动用RVO更好
【 在 mgroup 的大作中提到: 】
: 这样是不是更好些:
: std::vector<std::string> get_cmp_files(const std::string& dir);
: std::vector<std::string> v = std::move(get_cmp_files("cmp"));
: ...................
--
FROM 123.118.191.*