对于以下代码,我有点困惑,因为在使用g ++ -O3和g ++ -O1时,它们的行为有所不同。
#include <iostream>
#include <set>
#include <fstream>
#include <string>
#include <map>
#include <sstream>
int main(int argc, char** argv){
if(argc<=1){
std::cerr << "No Input File... Abort" << std::endl;
return 1;
}
std::ifstream in_file;
in_file.open(argv[1]);
if(!in_file) {
std::cerr << "Input \"" << argv[1] << "\" Could not be opened!... Abort" << std::endl;
return 1;
}
std::map<
std::pair<int,int> /*position,level*/ ,
int
> triangle;
int level=0; //Counter of current depth in the triangle
while(!in_file.eof()){
std::string line;
std::getline(in_file, line); //Read in complete line (level of triangle)
std::cout << line << std::endl; //Print what he read
std::istringstream iss (line); //Split line into pieces
for(int position=-level;position<=level;position+=2){ //Move through one level of the triangle
int value;
iss >> value;
std::pair<int,int> current_position(position,level); //Position in triangle
triangle.emplace(current_position, value); //Erzeugung des Punktes und Speicherung des Pointers in der Map
}
level++;
}
// Print out map contents
for(int i=0;i<level;++i){
for(int position=-i;position<=i;position+=2){
std::pair<int,int> current_position(position,i);
std::cout << triangle.at(current_position) << " ";
}
std::cout << std::endl;
}
return 0;
}
这个最小的例子只能读取一个文本文件,例如以下类型末尾带有空行:
1
2 3
我知道,如果文件末尾有一个空行,则循环中的字符串流将为空,从而导致流垃圾。但是,我不明白为什么使用-O3或-O1时行为会有所不同:
g++ test.cpp -Wall -pthread -pedantic -Wextra -O1 -std=c++11 -o test
./test test_file
1
2 3
1
2 3
3 3 3
g++ test.cpp -Wall -pthread -pedantic -Wextra -O3 -std=c++11 -o test
./test test_file
1
2 3
1
2 3
0 0 0
这已在我的系统上通过以下测试: gcc版本5.4.0 20160609(Ubuntu 5.4.0-6ubuntu1〜16.04.10)
如您所见,似乎-O3编译版本导致流忘记了它的最后输入,而-O1编译版本似乎存储了最后读入的值3,尽管应该在下一个循环中将其销毁。迭代。
答案 0 :(得分:4)
无论您的代码行为在不同的优化级别上是否不同,它都最有力地暗示该代码表现出未定义的行为(另一种选择是优化器中的一个bug,该bug确实存在,但存在很多可能性较小。)
原因是优化级别越低,编译器就越有可能将C ++代码机械地转换为ASM命令序列-完全按照书面规定。但是,随着优化水平的提高,编译器变得越来越有创造力,并开始对代码进行假设-思考的方式是编译器“相信”代码永远不会表现出未定义的行为,因此省略了所有只会被定义为“代码”的代码。如果存在未定义的行为,则执行该操作。