- 主题:这个右值引用返回有问题? 为什么一运行就segmentation fault?
std::vector<std::string>&& get_cmp_files(const std::string& dir) {
std::vector<std::string> res;
DIR* dp;
struct dirent* dirp;
if ((dp = opendir(dir.c_str())) == nullptr) {
printf("打开文件夹失败: %s, %s\n", dir.c_str(), strerror(errno));
exit(-1);
}
while ((dirp = readdir(dp)) != nullptr) {
if (dirp->d_type == DT_REG) {
res.emplace_back(dirp->d_name);
}
}
closedir(dp);
return std::move(res);
}
int main(int argc, char* argv[]) {
// std::string input_file;
// if (argc != 2) {
// printf("Usage: %s <input_file>\n", argv[0]);
// return -1;
// } else {
// input_file = argv[1];
// }
// Unpack upk;
// if (upk.unpack(input_file) != 0) {
// printf("解包文件失败, %s, 请查看日志\n", input_file.c_str());
// return -1;
// }
// 遍历cfile文件夹下的所有压缩文件, 拿到文件名
auto v = get_cmp_files("cmp");
if (v.size() > 0) {
Decompress dcp;
chdir("cmp"); // 将工作目录变更到cmp文件夹下, 方便后续处理
for (const auto& cmp_file : v) {
printf("开始解压缩文件, %s\n", cmp_file.c_str());
dcp.decode(cmp_file);
printf("解压缩文件结束, %s\n", cmp_file.c_str());
}
} else {
printf("此次下传中不包含图像压缩文件, 略过解压步骤\n");
}
printf("处理结束, GoodBye~~\n");
return 0;
}
RT, get_cmp_files函数的return std::move(res);一执行就崩溃...不明白为啥, 只是简单的不想vector值复制而已...难道我的右值引用和移动语义有问题? 用的gcc 9.4编译的
--
FROM 106.120.11.*
额, 我想的是不要vector值复制...如果直接返回左值, vector的内容不是会复制一份么
【 在 ziqin 的大作中提到: 】
: 你为何要返回一个rvalue?
:
--
FROM 106.120.11.*
那本来函数里面已经有一份了, 然后函数返回, main函数里面又复制了一份, 我想让main函数里面的vector直接指向子函数里面创建的那份堆的空间, 相当于指针换个指向
【 在 Bernstein 的大作中提到: 】
: 没听说返回右值引用的,直接返回值就行了
:
--
FROM 106.120.11.*
好的, 谢谢您的回答
【 在 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.*
好的,非常感谢您的回答,但是还有一点点小疑问想请教一下您。
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.*
好的,明白了,特别感谢您的耐心回答,谢谢!
【 在 z16166 的大作中提到: 】
: 理解不对
: 1、res是在函数返回之前已经被析构,其占用的堆内存释放了,占用的栈内存可能被覆盖/复用了。
: 一个已经无意义的变量res,其别名(左值引用、右值引用)、指针也等价于立即无效了,没有机会被函数外面的代码再来move走其内部的数据。
: ...................
--
FROM 219.142.184.*
好的, 谢谢您的耐心回答, 非常感谢!
【 在 poggy 的大作中提到: 】
:
: 这个理解是右值使用场景, 但不是发生在std::move 或 std::forward的调用,
: 这两个函数, 实际作用只是类型转换, 实际就是符号的语义解释在语言层面发生了变化,
: ...................
--
FROM 36.112.91.*