[英]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);
这不仅跳过了重新初始化,而且还跳过了创建过程。 由于该变量是在循环内部定义的,因此每次循环迭代时都会重新创建该变量。 如果跳过该创建,则无法使用。
如果要创建一次,则应将该行移出循环。
我将避免我的第一个倾向,那就是告诉您在同一句子中使用goto
和cleaner
通常是错误的-在某些情况下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.