使用istream_iterator填充vector避免拷贝及views::istream编译报错问题
两个C++流迭代器相关问题
问题1:消除istream_iterator读取含vector成员对象时的不必要拷贝
我发现这个问题和其他类似问题存在关键差异——我见过的相关帖子都会将迭代器元素拷贝至vector。我采用file->ifstream->istream_iterator->vector的常规写法(该方式会对vector的元素类型调用>>运算符),但根据cppreference文档,istream_iterator的解引用操作仅返回最近读取对象的拷贝。
我要读取的对象包含vector成员,这意味着当前读取的对象会被拷贝至vector中(需拷贝构造整个vector成员),而读取下一个对象时又会重新构造新对象,该拷贝完全多余且会拖慢程序性能。我想知道是否有办法消除此不必要的拷贝(我设想istream_iterator可以直接move对象,或者有其他方式避免拷贝)。
示例代码如下:
#include <fstream> #include <iostream> #include <iterator> #include <vector> struct My_class { std::vector<std::string> vec; // 用于展示构造函数调用情况的默认/拷贝/移动构造函数 My_class() : vec{} { std::cout << " default" << std::endl; } My_class(My_class const &other) : vec{other.vec} { std::cout << " copy" << std::endl; } My_class(My_class &&other) noexcept : vec{std::move(other.vec)} { std::cout << " move" << std::endl; } friend std::istream& operator>>(std::istream& is, My_class& i) { i.vec.clear(); // 因i仍保留前一个读取对象的数据,需清空 std::string l; // 其他用例中可能读取更多行,或对行预处理(如拆分)后插入vector std::getline(is, l); i.vec.push_back(l); return is; } }; int main(int argc, char* argv[]) { std::ifstream ifs{argv[1]}; std::vector<My_class> data{std::istream_iterator<My_class>{ifs}, {}}; for(const auto& _ele : data){ for(const auto& ele : _ele.vec){ std::cout << ele << " "; } std::cout << std::endl; } }
问题2:std::views::istream在Clang下编译报错
第二次尝试的代码:
#include <fstream> #include <iostream> #include <iterator> #include <vector> #include <memory> #include <ranges> static int cpy_cnt = 0; struct My_class { std::vector<std::string> vec; // 默认构造函数 My_class() : vec{} { std::cout << vec.size() << " default" << std::endl; } My_class(My_class&&) = default; My_class(const My_class&) = default; My_class& operator=(My_class&&) = default; My_class& operator=(My_class&) = default; friend std::istream& operator>>(std::istream& is, My_class& i) { i.vec.clear(); std::string l; std::getline(is, l); i.vec.push_back(l); return is; } }; int main(int argc, char* argv[]) { std::ifstream ifs{argv[1]}; std::cout << "iter create" << std::endl; auto tmp = std::views::istream<My_class>(ifs); std::cout << "vec create" << std::endl; std::vector<My_class> data2{}; }
这段代码在Clang下编译报错,错误信息包含error: no matching function for call to '__begin'(此处未粘贴完整长错误信息)。经GCC和Clang反复测试,该错误仅出现在Clang中,GCC可正常编译。
编译配置命令
- Clang编译命令:
cd build && cmake -DCMAKE_BUILD_TYPE=Debug -D CMAKE_C_COMPILER=clang -D CMAKE_CXX_COMPILER=clang++ -DCMAKE_EXPORT_COMPILE_COMMANDS=1 ..
- GCC编译命令:
cd build && cmake -DCMAKE_BUILD_TYPE=Debug -D CMAKE_C_COMPILER=gcc -D CMAKE_CXX_COMPILER=g++ -DCMAKE_EXPORT_COMPILE_COMMANDS=1 ..
编译器版本
$ g++ --version g++ (GCC) 12.2.0 Copyright (C) 2022 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ clang++ --version clang version 14.0.6 Target: x86_64-pc-linux-gnu Thread model: posix
内容的提问来源于stack exchange,提问作者atticus
相关产品推荐
相关产品推荐

