Goto 变量初始化之前导致编译器错误

发布于 2024-10-14 00:47:37 字数 3105 浏览 7 评论 0原文

考虑这段代码(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);
    }
}

如果它很重要的话:这是来自家庭作业的代码,用于过滤和修改文档中的单词。 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);
    }
}

这是否是一个好的设计选择目前无关紧要。编译器抱怨错误C2362:'words'的初始化被'goto SkipAndRestart'跳过

我不明白这个错误。为什么跳过初始化这个词很重要,而且是一个错误?这正是我想要发生的,我不想让它做更多的工作,只是重新开始该死的循环。 continue 宏不是做或多或少完全相同的事情吗?

Consider this code (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);
    }
}

If it's important: this is code from a homework assignment used to filter out and modify words in a document. document holds the document (previously read from file)

I wish to introduce a malicious goto because I think it's actually cleaner in this case like so:

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);
    }
}

Whether or not this is a good design choice is irrelevant at this moment. The compiler complains error C2362: initialization of 'words' is skipped by 'goto SkipAndRestart'

I don't understand this error. Why is it important, and an error, that the words initialization is skipped? That's exactly what I want to happen, I don't want it to do more work, just restart the bloody loop. Doesn't the continue macro do more or less the exact same thing?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

陌伤ぢ 2024-10-21 00:47:37

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

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

可以SkipAndRestart: 标签之后使用 words,这会是一个问题。在您的情况下,您不会使用它,但是 words 变量不会被破坏,直到引入它的作用域的end,因此只要对于编译器而言,该变量在标签点仍在使用中。

您可以通过将 words 放入其自己的作用域内来避免这种情况:

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

请注意,continue 语句跳转到循环的末尾,即您实际上可以'的位置贴上标签。这是循环内任何局部变量被销毁之后、跳回到循环顶部之前的点。

You are skipping over the construction of the words array:

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

You could have used words after the SkipAndRestart: label, which would have been a problem. You don't use it in your case, but the words variable won't be destructed until the end of the scope in which it is introduced, so as far as the compiler is concerned, the variable is still in use at the point of the label.

You can avoid this by putting words inside its own scope:

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

Note that the continue statement jumps to the end of the loop, at a point where you actually can't put a label. This is a point after the destruction of any local variables inside the loop, but before the jump back up to the top of the loop.

归途 2024-10-21 00:47:37

使用该goto,您将跳过该行:

std::vector<std::string> words = Utility::split(line);

这不仅仅是跳过重新初始化,而是跳过创建。由于该变量是在循环内部定义的,因此每次循环迭代时都会重新创建它。如果您跳过该创建,则无法使用它。

如果您希望它创建一次,则应该将该行移到循环之外。

我会避免我的第一个倾向,即告诉您在同一个句子中使用 gotocleaner 通常是错误的 - 在某些情况下 goto< /code> 更好,但我不确定这是其中之一。我要告诉你的是,如果这是家庭作业,goto 是一个坏主意 - 任何教育者都会对使用 goto 皱眉。

With that goto, you are skipping the line:

std::vector<std::string> words = Utility::split(line);

This isn't just skipping the re-initilisation, it's skipping the creation. Because that variable is defined inside the loop, it's created freshly each time the loop iterates. If you skip that creation, you can't use it.

If you want it created once, you should move that line outside of the loop.

I'll refrain from my first inclination, which is to tell you that using goto and cleaner in the same sentence is usually wrong - there are situations where goto is better but I'm not sure this is one of them. What I will tell you is that, if this is homework, goto is a bad idea - any educator will frown upon the use of goto.

欲拥i 2024-10-21 00:47:37

一如既往,当有人认为 goto 会使代码更具可读性时,重构以使用(内联)函数至少和没有 goto 一样好:

// Beware, brain-compiled code ahead!
inline void WordManager::giveThisAMeaningfulName(const std::string& word, std::string__size_type currentLineNo)
{
    Utility::trim(word, WordManager::delims);
    Utility::normalize(word, WordManager::replace, WordManager::replaceWith);
    if(ruleOne(word) && ruleTwo(word))
    {
        std::set<Word>::iterator sWIter(words_.find(Word(word)));
        if(sWIter == words_.end())
            words_.insert(Word(word)).first->addLineNo(currentLineNo);
        else
            sWIter->addLineNo(currentLineNo);
    }
}

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

    std::string line;
    while(std::getline(line))
        if(line.size() > 1)
        {
          std::vector<std::string> words = Utility::split(line);
          if(word.size() > 1)
              for(unsigned int i(0); i < words.size(); ++i)
                  giveThisAMeaningfulName(words[i], currentLineNo++);
        }
}

我没有我不想费心去理解那个内部循环的作用,所以我让你给它一个有意义的名字。请注意,一旦您给了它一个名称,我就不需要了解它的算法来了解它的作用,因为名称说明了一切。)

请注意,我已将您手写的行提取替换为 < code>std::getline(),这使得代码更小。

As always when someone thinks goto would code more readable, refactoring to use (inline) functions is at least as good and without goto:

// Beware, brain-compiled code ahead!
inline void WordManager::giveThisAMeaningfulName(const std::string& word, std::string__size_type currentLineNo)
{
    Utility::trim(word, WordManager::delims);
    Utility::normalize(word, WordManager::replace, WordManager::replaceWith);
    if(ruleOne(word) && ruleTwo(word))
    {
        std::set<Word>::iterator sWIter(words_.find(Word(word)));
        if(sWIter == words_.end())
            words_.insert(Word(word)).first->addLineNo(currentLineNo);
        else
            sWIter->addLineNo(currentLineNo);
    }
}

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

    std::string line;
    while(std::getline(line))
        if(line.size() > 1)
        {
          std::vector<std::string> words = Utility::split(line);
          if(word.size() > 1)
              for(unsigned int i(0); i < words.size(); ++i)
                  giveThisAMeaningfulName(words[i], currentLineNo++);
        }
}

I haven't bothered trying to understand what that inner loop does, so I leave it to you to give it a meaningful name. Note that, once you have given it a name, I don't need to understand its algorithm in order to know what it does, because the name says it all.)

Note that I have replace your hand-written line-extraction by std::getline(), which made the code even smaller.

今天小雨转甜 2024-10-21 00:47:37

另一种解决方案是在“if”指令之前声明“words”(以防您确实无法填充“if”上方的向量)并稍后填充该向量

// HERE!!!!!!
std::vector<std::string> words;
if(line.size() < 2)
     goto SkipAndRestart;
words = Utility::split(line);

Another solution would be just to declare 'words' before the 'if' instruction (in case you really can't populate the vector above the 'if') and populate the vector later

// HERE!!!!!!
std::vector<std::string> words;
if(line.size() < 2)
     goto SkipAndRestart;
words = Utility::split(line);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文