【发布时间】:2015-02-04 07:32:14
【问题描述】:
在我的 gcc-4.8.1 上,我使用两个命令编译了以下程序:
g++ -Wfatal-errors -std=c++11 -Wall -Werror test.cpp -o test -g
g++ -Wfatal-errors -std=c++11 -Wall -Werror test.cpp -o test -O3 -g
第一个可执行文件具有预期的输出,但第二个可执行文件有段错误。问题是它很难调试,因为-O3 与代码混淆太多,-g 调试信息无法保留意义,所以gdb 很难翻译源代码中发生的事情。所以,我开始插入打印语句。正如我所料,打印语句改变了结果。使用调试打印,它工作得很好!
这是我的表达式模板来源:
//test.cpp
#include <vector>
#include <stdlib.h>
#include <iostream>
using namespace std;
typedef vector<int> Valarray;
template<typename L, typename R>
struct BinOpPlus {
const L& left;
const R& right;
BinOpPlus(const L& l, const R& r)
: left(l), right(r)
{}
int operator[](int i) const {
int l = left[i];
//cerr << "Left: " << l << endl; //uncomment to fix segfault
int r = right[i];
//cerr << "Right: " << r << endl; //uncomment to fix segfault
return l + r;
}
};
template<typename L, typename R>
BinOpPlus<L, R> operator+(const L& left, const R& right){
return BinOpPlus<L, R>(left, right);
}
int main() {
//int size = 10000000;
int size = 10;
Valarray v[3];
for(int n=0; n<3; ++n){
for(int i=0; i<size; ++i){
int val = rand() % 100;
v[n].push_back(val);
}
}
auto out = v[0] + v[1] + v[2];
int sum = 0;
for(int i=0; i<size; ++i){
cerr << "Checkpoint!" << endl;
sum += out[i]; //segfaults here
cerr << "Sum: " << sum << endl;
}
cout << "Sum: " << sum << endl;
return 0;
}
-O3 给我一个不正确/不可靠的二进制文件已经很久了。我首先假设我在代码中做错了什么,但还不足以让-O0 显示出来。有人知道我做错了什么吗?
【问题讨论】:
-
为什么哦,为什么有人要这样做?
-
有趣的是,您将运行此代码导致的分段错误称为“令人费解的”。我称之为“令人困惑”的是(1)这种代码背后的动机,以及(2)你认为
main中的auto实际上有什么类型(我实际上不知道答案这个)。 -
@Andrey 我没有看到问题。 ET 算术的一般概念对我来说似乎是合理的,它只是一个实现问题。
-
@Andrew (1) 向量算术,无需将向量复制到临时向量等。求和不需要使用表达式模板分配向量,而更直观的方法是创建一个或两个额外的临时向量,并为累加创建另外 1 个额外的局部向量。如果没有内存分配,累积会快得多。 (2) sbabbi 是正确的,因为它是
BinOpPlus< BinOpPlus<ValArray, ValArray>, Valarray>。不过,表达式模板类型确实无关紧要。