使用 -O3 使用 g++ 编译时C++程序中的分段错误
Segmentation fault in a C++ program when compiling with g++ using -O3
当我使用 g++(版本 4.9.1(编译以下代码时,它适用于非优化或使用 -O2 进行优化。但是,当使用 -O3 编译时,程序在第 30 行崩溃并打印"分段错误(核心转储("。
我试图保持尽可能简单。我还注意到,删除(看似(不重要的部分,例如成员变量单词,似乎可以解决问题。我在这里做错了什么?
#include <iostream>
#include <stdlib.h>
using namespace std;
char *curMemPos2=NULL; //The first free pos in allocated memory
class Dictionary{
public:
int numWords;
int* words;
double* wordFrequency;
Dictionary(int nw){
numWords = nw;
wordFrequency = NULL;
wordFrequency = (double*)curMemPos2;
curMemPos2 += (sizeof(double)*numWords);
words = NULL;
words = (int*)curMemPos2;
curMemPos2 += (sizeof(int)*numWords);
if (wordFrequency == NULL || words == NULL) {
cout << "could not allocate memory" << endl;
exit(0);
}
}
void addwords(){
for (int i = 0; i < numWords; i++){
wordFrequency[i] = i * 0.2;
}
}
};
int main(){
curMemPos2 = (char*) malloc(1024 * 1024);
if (curMemPos2 == NULL) {
cout << "could not allocate initial memory" << endl;
exit(0);
}
for (int i = 5; i < 10; i++){
cout << "--------------------------" << endl;
cout << "initializing dict with " << i << " words" << endl;
Dictionary d = Dictionary(i);
cout << "adding words" << endl;
d.addwords();
}
}
您似乎正在尝试在此处执行基于内存池的分配器,这通常不是一个坏主意。(不过,该实现可能需要大量改进。
您遇到的问题是对齐。 int
可能是 4 字节对齐的。 double
可能是 8 字节对齐的。
malloc
返回的地址始终适合具有基本对齐要求的任何类型的对象 - 因此对于int
或double
,它始终对齐良好。当您尝试分配奇数个 int
s 时,会出现此问题。假设 malloc
返回地址0x3000
并且您分配了 5 个int
,然后 curMemPos2
的地址变为 0x3014
,然后您尝试分配 5 个double
s - 但0x3014
不是double
的有效地址,因为它不是 8 字节对齐的。
事实上,它不适用于优化,而它没有工作,这表明您的代码中存在一些未定义的行为,在某些情况下(不幸(有效。
您在这里有几个候选人:
- 如果两个不同类型的指针(例如
int *words
和double *wordfrequency
( 将指向相同的内存位置,将不遵守严格的混叠。 严格别名是关于编译器对指针所做的假设,以便进一步优化代码。 - 有时添加到全局
curMemPos2
指针sizeof(int)
有时添加到sizeof(double)
。 即使您的初始指针可能符合所有类型的对齐方式,如果优化器尝试使用具有对齐要求的特殊 CPU 操作,则您的cumMemPos2
也可能在某个时刻不符合double
导致邪恶的对齐要求。 - 您的自制分配方案不控制上限:您将永远递增
curMemPos2
并且您的指针有一天可能会指向未分配的内存(此处不会将它们设置为 NULL(。但是,好的,此项目符号不是问题的原因,因为您只分配了几个条目。
建议:
由于每个Dictionary
构造都使用自我管理的内存池中的数字字int
和数字double
字,因此我建议使用受保护的结构:
class Dictionary{
protected:
struct mbloc { // with a struct, the compiler takes care of alignment requ.
double frequency;
int words;
};
public:
... // allocate mbloc *entries instead of *int and *doubles;
};
使用这种方法,您可以考虑使用 new
来分配一个干净的 mbloc 数组,甚至可能是一个vector<mbloc>
。
相关文章:
- 在某些循环内使用vector.push_back时出现分段错误
- Windows 10-使用gtkmm-3.0库和g++[包括再现]的分段故障
- 尝试使用集合函数时出现分段错误
- g++的分段错误(在NaN上使用to_string两次时)
- 使用 CTYPE 时出现分段错误
- 使用静态库与 std::jthread (g++-10) 的分段错误
- 分段错误(核心转储) - 使用 SavedModel 的 Tensorflow C++ API 进行推断
- 在 boost::qi 中使用过多的替代运算符会导致分段错误
- 使用 lua 协程 API 和lua_close时出现分段错误
- 在使用堆栈为下一个最大数字编写代码时面临 SIGSEGV(分段错误)
- 面临分段故障 使用 ffmpeg 读取视频时,因为"pFormatCtx-> streams [i]-> codecpar"的地址0x00
- 使用 AWS C++ 开发工具包分段上传 S3
- 为什么我使用 std::copy() 收到运行时错误(分段错误)?
- 当我使用 V8 库中的 GetInternalField() 时出现分段错误
- C++OpenSSL RSA_free如果也使用EVP_PKEY_free,则会给出分段错误
- 分段 使用 MPI_Gather 收集字符数组时出错
- 使用谷歌测试进行测试时出现分段错误
- 为什么在环路条件中使用'<='而不是'<'会产生分段错误 [SIGSEGV]?
- 在类和构造函数中使用向量时出现分段错误
- 在使用分段寻址模式的 16 位系统上,"size_t"、"uintptr_t"、"intptr_t"和"ptrdiff_t"类型的实际大小是多少?