令人困惑的表达式模板与 O3 的隔离错误
Befuddling Expression Template Segfault with O3
在我的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
无法证明它。 有人知道我做错了什么吗?
在这一行中
auto out = v[0] + v[1] + v[2];
out
的类型是 BinOpPlus< BinOpPlus<ValArray, ValArray>, Valarray>
.由于您的BinOpPlus
存储对其参数的引用,并且BinOpPlus<ValArray,ValArray>
是临时的,因此您具有未定义的行为。
通常像这样的表达式模板使用特征来决定如何存储它们的参数,以便您可以通过引用(并假设用户不会搞砸)和其他 ET 按值存储(无论如何它们都非常小)。
此外,将auto
与算术 ET 一起使用至少被认为是有问题的,因为它很少产生预期的类型。正是出于这个原因,有一些建议引入一种operator auto
来自定义 ET 中自动推断的类型。
这是一种预感。
在行中
auto out = v[0] + v[1] + v[2];
你有临时对象。这可能会被-O3
标志删除。我会尝试以下方法:
auto out1 = v[1] + v[2];
auto out = v[0] + out1;
将代码更改为不使用结构中的引用成员。 我相信当您在此处进行添加时,引用成员会使复制操作变得混乱:
auto out = v[0] + v[1] + v[2];
例如:
template<typename L, typename R>
struct BinOpPlus {
const L left;
const R right;
进行此更改可以正常工作。
另外,仅供参考,当使用带有完整警告(/W4
)的Visual Studio 2013
编译代码时,我们收到以下警告:
警告 C4512:"BinOpPlus":无法生成赋值运算符。
因此,这表明任何复制都可能产生不良影响。
没有参考的良好运行的现场示例:http://ideone.com/JKxoDv
带有引用的错误运行的实时示例:http://ideone.com/7oSoJB
- 带内存和隔离功能的SQLite
- 使用不同的CRT将新的C++代码与旧的(二进制)组件隔离开来的最佳方法是什么
- 如何使用隔离>终止执行来停止所有线程
- 从矢量中删除元素后出现隔离错误
- 在 gtest 中初始化堆栈上的引用变量的隔离错误
- 线程时访问静态映射时出现隔离错误
- C++ - 优化矩阵乘法来自后藤一重的论文,在 O3 标志中表现比幼稚差
- 比特币隔离见证钱包地址计算
- 并行快速排序分区中的隔离错误
- g++ -O3 为 loop 创建了奇怪的指令 - 两个具有相同 asm 的版本
- C++多线程程序:变量定义为类成员的隔离错误
- clang:使用 O3 导出隐式实例化函数的符号
- TFLite 隔离错误,通过获取C++输入和输出
- 我只是在寻找模板,在我的书中找到了这段代码,这显示了隔离错误?
- 如何将 v8::FunctionCallbackInfo<v8::Value> 数组从一个隔离复制到另一个隔离?
- pthread_create中错误 4 的隔离错误
- 如何构建与操作系统隔离的节点插件api
- 隔离位并展平它们
- 递归树遍历/分支删除的隔离错误
- 令人困惑的表达式模板与 O3 的隔离错误