Std::istringstream.good()比预期多返回一次true
std::istringstream.good() returns true once more than expected
我正在制作一个玩具程序,从字符串创建类(例如,我输入它"test1 test2",它使test1.cpp, test1.h, test2.cpp, test2.h)
动作发生在这个函数中:
bool makeClassesFromString(std::string classNames){
bool returnValue = true;
if (classNames == ""){
returnValue = false;
}
else{
std::istringstream issClassNames (classNames);
std::string sClassName;
while(issClassNames.good()){
issClassNames >> sClassName;
std::string sourceName = sClassName;
sourceName += ".cpp";
std::string headerName = sClassName;
headerName += ".h";
std::ofstream source(sourceName.c_str()), std::ios::app);
std::ofstream header(headerName.c_str()), std::ios::app);
//source << "#include "" << headerName << """;
source.close();
header.close();
}
}
return returnValue;
}
文件以追加模式打开,以确保任何已经存在的类不会被意外覆盖。
我最近回到这个程序,包括一些额外的-特别是,旧版本只创建了两个空文件,我想修改它,以创建具有必要的定义和包含的文件,这样我就不必每次都手动进入并添加它们。这揭示了意想不到的行为——最后一个要创建的类会将任何文本添加两次。
在上面的代码示例中,我已经注释掉了我开始处理这个问题的行,但是当我不注释掉它时,我得到了这样的行为:
input:
classmaker.exe test1 test2
output:
test1.h
test2.h
test1.cpp //(Which contains: #include "test1.h")
test2.cpp //(Which contains: #include "test2.h"#include "test2.h"
我的猜测是,我的while(issClassNames.good())
返回一个额外的时间与最后一个类名(因此再次将字符串追加到源文件),但我不确定是什么行为驱动这。
目前提出的解决方案:
- 在以
ofstream
模式打开文件之前,测试以ifstream
模式打开文件是否已经存在。(问题:没有解决运行while
一次模式的问题,而不是必要的) - 删除追加模式。(问题:有可能覆盖已经存在的类,仍然不能解决while-loop问题)
- 在while-loop中使用条件测试,不要在上次运行时打开文件,例如,比较当前类名和上次类名并终止如果相等。问题:不确定如何检查这是否是最后一次运行,除了模糊的"这是上一次相同的类名吗?"测试,如果输入字符串是"test1 test1 test2",也可能有过早中止的风险
编辑
我已经意识到:并不是istringstream.good()比预期多返回一次true,而是它的计算结果是这样的:
input: "test1 test2"
evaluation:
good = true; extract next to string //(succeeds, overwrites empty string with "test1")
good = true; extract next to string //(succeeds, overwrites "test1" with "test2")
good = true; extract next to string //(fails, Doesn't overwrite "test2")
good = false; break loop.
EDIT 2 + 3
这很容易解决。谢谢你们所有人。不幸的是,我只能标记一个答案作为接受,所以我选择了第一个张贴的答案,但我感谢帮助。
最后一个完整的程序:
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
void makeClassesFromStdInput();
void makeClassesFromParameter(int argc, const char** argv);
bool makeClassesFromString(std::string classNames);
int main(int argc, const char** argv){
switch (argc) {
case 0: //This shouldn’t happen
break;
case 1:
//This will keep making classes from the CLI until
//the user breaks the process.
makeClassesFromStdInput();
break;
default:
//This will make classes from the parameters passed
//to the program except the first parameter which is
//assumed to be the program name.
makeClassesFromParameter(argc, argv);
break;
}
return 0;
}
void makeClassesFromStdInput(){
std::cout << "Input class name and press enter.nWhitespace delimits class names.nA blank line ends the process.n>";
bool running = true;
std::string classNames;
while(running){
std::getline(std::cin, classNames);
running = makeClassesFromString(classNames);
}
}
void makeClassesFromParameter(int argc, const char** argv){
std::string classNames = "";
for(int i = 1; i<argc; i++){
classNames += argv[i];
classNames += " ";
}
makeClassesFromString(classNames);
}
bool makeClassesFromString(std::string classNames){
bool returnValue = true;
if (classNames == ""){
returnValue = false;
}
else{
std::istringstream issClassNames (classNames);
std::string sClassName;
while(issClassNames >> sClassName){
std::string sourceName = sClassName;
sourceName += ".cpp";
std::string headerName = sClassName;
headerName += ".h";
std::ofstream source(sourceName.c_str(), std::ios::app);
std::ofstream header(headerName.c_str(), std::ios::app);
source << "#include "" << headerName << """;
//Header is slightly more involved because we want all capital letters
for (std::string::size_type i=0; i<headerName.length(); ++i){
if(headerName[i] == '.'){
headerName[i] = '_';
}
else{
headerName[i] = toupper(headerName[i]);
}
}
header << "#ifndef __" << headerName << "n"
<< "#define __" << headerName << "n"
<< "n"
<< "n"
<< "#endif";
source.close();
header.close();
}
}
return returnValue;
}
流不知道你要读什么。如果读取尝试成功,您总是需要在之后检查:
while(issClassNames >> sClassName) {
// do whatever processing of sClassName you want to do
}
尝试更改:
while(issClassNames.good()){
:
while(issClassNames >> sClassName){
并将这一行从循环的顶部取出
流操作符>>
返回一个流,该流可以被强制转换为bool类型,其结果为good()
的结果。由于返回的流是在调用>>
之后的状态,如果操作设置了eof
位,它将返回false。
你应该替换
while(issClassNames.good()){
issClassNames >> sClassName;
while(issClassNames >> sClassName) {
为什么
假设您的输入是test1 test2
。你首先检查流是否正常。由于没有错误,所以您可以在sClassName
中阅读test1
。现在流仍然是正常的,所以继续在sClassName
中读取test2
(在这一步中没有错误)。流仍然很好,所以你继续尝试再次读取,但是operator >>
失败,sClassName
保持不变,因此你看到的是旧值test2
。
operator >>
返回流本身的句柄(可转换为bool
),可以在condition中使用。因此,只有当读取成功时才会进入循环。
- flutter:即使shouldRepaint()返回true,自定义画家也不会重新绘制
- C++如果使用 lambda 表达式的语句返回 true,但输出来自 false,为什么
- MFC 的 OnInit() 函数中的返回 true 和返回 false 有什么区别
- 我正在尝试创建一个布尔函数,该函数计算字符并在字符为"()*-+"时返回 true
- 创建一个函数,如果元素在unordered_set中,则返回 true,如何处理模板
- QTimer isActive 返回 true,但 remainingTime 返回 -1
- 为什么在 IsValid(Object) 返回 true 后不能安全地使用 Object?
- 计算 <Classtype*> 向量中所有项的布尔值的最有效方法,如果全部为真则返回 true
- QDir mkpath 返回 true,但未创建目录
- std::is_array 当它应该返回 false 时返回 true
- 尝试创建一个评估字符的bool函数,如果字母数字为字母,则返回true
- 我想返回 True/False 关于值是否在一组值中
- 为什么我的布尔函数返回 true 会导致读取访问冲突?
- ifstream::is_open 返回 true,即使该位置不存在文件也是如此
- 为什么包含指针的条件总是返回 true?
- 对于 ((无符号整数)0-1)返回 true>0
- 为什么#ifndef __func__返回true
- 我的bool函数一直返回true,我不知道为什么
- 对表达式求值,直到表达式返回true
- 在{8,4,6,2}中搜索4时,std::binary_search是否有任何实现将返回true