【问题标题】:std::istringstream.good() returns true once more than expectedstd::istringstream.good() 比预期返回 true 一次
【发布时间】:2014-07-14 22:08:54
【问题描述】:

我正在制作一个玩具程序来从字符串创建类(例如,我将其输入为“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()) 会返回一个带有最后一个类名的额外时间(因此再次将字符串附加到源文件),但我不确定是什么行为导致了这种情况。

目前提出的解决方案:

  1. 在以ofstream 模式打开之前,测试是否已存在试图以ifstream 模式打开的文件。 (问题:不能解决运行while 一次模式而不是必要的问题)
  2. 删除附加模式。 (问题:有覆盖已经存在的类的风险,仍然不能解决 while-loop 问题)
  3. 在 while 循环中使用条件测试,不要在上次运行时打开文件,例如将当前类名与上一个类名进行比较,如果相等则中止。问题:不知道如何检查这是否是最后一次运行,除了cludgy“这与上次的类名相同吗?”如果输入字符串是“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.

编辑 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;

}

【问题讨论】:

    标签: c++ string while-loop


    【解决方案1】:

    你应该替换

    while(issClassNames.good()){
      issClassNames >> sClassName;
    

    while(issClassNames >> sClassName) {
    

    为什么
    假设您的输入是test1 test2。你首先检查流是好的。因为没有错误,所以你在sClassName 中阅读test1 很好。现在流仍然很好,所以你继续阅读test2 in sClassName(这一步没有错误)。流仍然很好,因此您继续尝试再次读取,但 operator &gt;&gt; 失败并且 sClassName 保持不变,因此您会看到旧值 test2

    operator &gt;&gt; 将句柄返回到流本身(可转换为bool),我们可以在条件下使用。所以只有读取成功才会进入循环。

    【讨论】:

      【解决方案2】:

      尝试改变:

      while(issClassNames.good()){
      

      到:

      while(issClassNames >> sClassName){
      

      然后将那条线从循环的顶部取出。

      流运算符&gt;&gt; 返回一个流,它可以转换为布尔值,结果是good() 的结果。由于返回的流是&gt;&gt;调用后的状态,如果eof被操作置位则返回false。

      【讨论】:

        【解决方案3】:

        流无法知道您将要阅读的内容。如果您的阅读尝试成功,您始终需要检查 您尝试阅读后:

        while(issClassNames >> sClassName) {
            // do whatever processing of sClassName you want to do
        }
        

        【讨论】:

        • 真正奇怪的是,我在进入stackoverflow之前就想到了这个解决方案,但在考虑之前立即将其丢弃为不可行。我一点也不知道为什么会这样。
        猜你喜欢
        • 2011-12-03
        • 1970-01-01
        • 1970-01-01
        • 2021-01-11
        • 1970-01-01
        • 1970-01-01
        • 2021-01-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多