在变量初始化之前转到Goto导致编译错误

IAE*_*IAE 7 c++ goto

考虑一下这段代码(VS2008):

void WordManager::formatWords(std::string const& document)
{
    document_ = document;
    unsigned int currentLineNo = 1;

    size_t oldEndOfLine = 0;
    size_t endOfLine    = document_.find('\n');
    while(endOfLine != std::string::npos)
    {
        std::string line = document_.substr(oldEndOfLine, (endOfLine - oldEndOfLine));
        if(line.size() < 2)
        {
            oldEndOfLine = endOfLine + 1;
            endOfLine    = document_.find('\n', oldEndOfLine);
            continue;
        }

        std::vector<std::string> words = Utility::split(line);
        for(unsigned int i(0); i < words.size(); ++i)
        {
            if(words[i].size() < 2)
                continue;
            Utility::trim(words[i], WordManager::delims);
            Utility::normalize(words[i], WordManager::replace, WordManager::replaceWith);

            if(ruleOne(words[i]) && ruleTwo(words[i]))
            {
                std::set<Word>::iterator sWIter(words_.find(Word(words[i])));

                if(sWIter == words_.end())
                    words_.insert(Word(words[i])).first->addLineNo(currentLineNo);
                else
                    sWIter->addLineNo(currentLineNo);
            }
        }
        ++currentLineNo;

        oldEndOfLine = endOfLine + 1;
        endOfLine    = document_.find('\n', oldEndOfLine);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果它很重要:这是来自用于过滤和修改文档中的单词的家庭作业的代码.document持有文件(以前从文件中读取)

我想介绍一个恶意的goto,因为我认为它在这种情况下实际上更清洁:

void WordManager::formatWords(std::string const& document)
{
    document_ = document;
    unsigned int currentLineNo = 1;

    size_t oldEndOfLine = 0;
    size_t endOfLine    = document_.find('\n');
    while(endOfLine != std::string::npos)
    {
        std::string line = document_.substr(oldEndOfLine, (endOfLine - oldEndOfLine));
        // HERE!!!!!!
        if(line.size() < 2)
            goto SkipAndRestart;

        std::vector<std::string> words = Utility::split(line);
        for(unsigned int i(0); i < words.size(); ++i)
        {
            if(words[i].size() < 2)
                continue;
            Utility::trim(words[i], WordManager::delims);
            Utility::normalize(words[i], WordManager::replace, WordManager::replaceWith);

            if(ruleOne(words[i]) && ruleTwo(words[i]))
            {
                std::set<Word>::iterator sWIter(words_.find(Word(words[i])));

                if(sWIter == words_.end())
                    words_.insert(Word(words[i])).first->addLineNo(currentLineNo);
                else
                    sWIter->addLineNo(currentLineNo);
            }
        }

SkipAndRestart:
        ++currentLineNo;

        oldEndOfLine = endOfLine + 1;
        endOfLine    = document_.find('\n', oldEndOfLine);
    }
}
Run Code Online (Sandbox Code Playgroud)

目前这是否是一个好的设计选择是无关紧要的.编译器抱怨error C2362: initialization of 'words' is skipped by 'goto SkipAndRestart'

我不明白这个错误.为什么跳过单词初始化很重要,也是错误的?这正是我想要发生的事情,我不希望它做更多工作,只需重新启动血腥循环.继续宏不是或多或少完全相同吗?

Gre*_*ill 19

你正在跳过words数组的构造:

    if(line.size() < 2)
        goto SkipAndRestart;
    std::vector<std::string> words = Utility::split(line);
    // ...
SkipAndRestart:
Run Code Online (Sandbox Code Playgroud)

可能已经使用wordsSkipAndRestart:的标签,这将是一个问题.你不要在你的情况下使用它,但是在引入words变量的范围结束之前不会破坏变量,因此就编译器而言,变量仍在使用中.标签.

您可以通过放入words自己的范围来避免这种情况:

    if(line.size() < 2)
        goto SkipAndRestart;
    {
        std::vector<std::string> words = Utility::split(line);
        // ...
    }
SkipAndRestart:
Run Code Online (Sandbox Code Playgroud)

请注意,continue语句跳转到循环的末尾,在实际上无法放置标签的位置.这是在循环内部任何局部变量被破坏之后,但在跳回到循环顶部之前的一个点.