为何C++中初始化stringstream时调用string的erase函数无效?
问题分析与解决
问题描述
读取同目录下文本文件,文件内容仅一行:" v 1.0 2.0 3.0"。调用line.erase(0,1)后初始化stringstream,发现'v'并未被移除,输出和未调用erase时一致。代码如下:
#include <sstream> #include <fstream> #include <iostream> int main() { std::ifstream filestream("textfile.txt", std::ios::in); std::string line = ""; while (!filestream.eof()) { std::getline(filestream, line); std::cout <<"getline std::string "<< line.c_str()<<std::endl; std::stringstream ss(line.erase(0,1)); std::cout << "stringstream: " << ss.str() << std::endl; } }
原因解析
- erase操作对象错误:你的文件内容开头是空格,不是
'v'。erase(0,1)移除的是字符串的第一个字符(空格),剩下的字符串是"v 1.0 2.0 3.0",所以输出中仍会看到'v'。 - 循环条件的坑:
while (!filestream.eof())的写法会导致最后一次循环重复执行——当getline读取完最后一行后,eof标志不会立即置位,循环会再跑一次,此时line是上一次的内容(或空),可能引发错误输出。
修复方案
方案1:精准移除目标字符
先跳过开头空白字符,再定位'v'进行删除,同时修正循环条件:
#include <sstream> #include <fstream> #include <iostream> int main() { std::ifstream filestream("textfile.txt", std::ios::in); std::string line; // 用getline返回值判断读取是否成功,避免eof判断的坑 while (std::getline(filestream, line)) { std::cout <<"getline std::string: "<< line <<std::endl; // 跳过开头的空白字符 size_t start_pos = line.find_first_not_of(" \t"); if (start_pos != std::string::npos && line[start_pos] == 'v') { line.erase(start_pos, 1); } std::stringstream ss(line); std::cout << "stringstream: " << ss.str() << std::endl; } }
方案2:用stringstream直接跳过'v'
更贴合OBJ加载逻辑的做法:直接从stringstream中读取并丢弃第一个token('v'),无需修改原字符串:
#include <sstream> #include <fstream> #include <iostream> #include <string> int main() { std::ifstream filestream("textfile.txt", std::ios::in); std::string line; while (std::getline(filestream, line)) { std::cout <<"getline std::string: "<< line <<std::endl; std::stringstream ss(line); std::string token; // 读取并丢弃第一个token(即'v') ss >> token; // 读取后续数值 float x, y, z; ss >> x >> y >> z; std::cout << "提取的数值:x=" << x << ", y=" << y << ", z=" << z << std::endl; } }
内容的提问来源于stack exchange,提问作者pg daszzz
相关产品推荐
相关产品推荐

