簡體   English   中英

在變量初始化導致編譯器錯誤之前轉到

[英]Goto before variable initialization causes compiler error

考慮以下代碼(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);
    }
}

目前,這是否是一個好的設計選擇並不重要。 編譯器抱怨error C2362: initialization of 'words' is skipped by 'goto SkipAndRestart'

我不明白這個錯誤。 跳過初始化一詞為什么很重要且有錯誤? 那正是我想要發生的事情,我不希望它做更多的工作,只是重新開始流血的循環。 連續宏不是完全一樣嗎?

您將跳過words數組的構建:

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

可能SkipAndRestart:標簽之后使用了words ,這可能是一個問題。 您不會在自己的情況下使用它,但是直到引入變量的作用域結束時words variables才會被破壞,因此就編譯器而言,該變量在標簽。

您可以通過在其自己的范圍內放置words來避免這種情況:

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

請注意, continue語句跳到循環的末尾,此時您實際上無法放置標簽。 這是在破壞循環內的任何局部變量之后,但在跳回到循環頂部之前的一點。

使用goto ,您可以跳過以下行:

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

這不僅跳過了重新初始化,而且還跳過了創建過程。 由於該變量是在循環內部定義的,因此每次循環迭代時都會重新創建該變量。 如果跳過該創建,則無法使用。

如果要創建一次,則應將該行移出循環。

我將避免我的第一個傾向,那就是告訴您在同一句子中使用gotocleaner通常是錯誤的-在某些情況下goto會更好,但我不確定這是其中的一種。 我要告訴你的是,如果這是家庭作業,那么goto是個壞主意-任何教育者都會對goto的使用goto

和往常一樣,當有人認為goto代碼更易讀時,使用( inline )函數進行重構至少和不使用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++);
        }
}

我沒有費心去嘗試了解內循環的作用,所以我給你起一個有意義的名字。 請注意,一旦給它起了一個名字,我就不需要了解它的算法就可以知道它的作用,因為這個名字說明了一切。)

請注意,我用std::getline()替換了您的手寫行提取,這使代碼更小了。

另一種解決方案是僅在“ if”指令之前聲明“ words”(以防您真的無法在“ if”上方填充矢量),然后再填充矢量

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM