当我使用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();
}
}
答案 0 :(得分:2)
你似乎试图在这里做一个基于内存池的分配器,这一般不是一个坏主意。 (但实现可能会使用很多改进。)
你遇到的问题是对齐。 int
可能是4字节对齐的。 double
可能是8字节对齐的。
malloc
返回的地址始终适合任何类型的具有基本对齐要求的对象 - 因此它始终与int
或double
完全一致。当您尝试分配奇数个int
时会发生此问题。假设malloc
返回地址0x3000
并且您分配了五个int
,那么curMemPos2
的地址变为0x3014
,然后您尝试分配五个double
1}} s - 但0x3014
不是double
的有效地址,因为它不是8字节对齐的。
答案 1 :(得分:1)
它没有使用优化,而它没有工作,这表明你的代码中有一些未定义的行为,在某些情况下(un)幸运的是。
你有几个候选人:
int *words
和double *wordfrequency
)指向相同的内存位置,则strict aliasing将不会被尊重。严格别名是关于编译器对指针的假设,以便进一步优化代码。 curMemPos2
有时sizeof(int)
添加到您的全局sizeof(double)
指针。即使您的初始指针可能符合所有类型的对齐,但有可能在cumMemPos2
时,如果优化程序尝试使用特殊对象,则double
不符合curMemPos2
导致恶意的对齐要求具有对齐要求的cpu操作。 Dictionary
你的指针可能有一天指向未分配的内存(这里没有任何东西会将它们设置为NULL)。但好吧,这个子弹不是你问题的原因,因为你只分配了几个条目。 建议:
由于每个int
构造在自我管理的内存池中使用 numwords double
和 numwords 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;
};
,因此我可以使用#{1}}构造。 d建议使用受保护的结构:
new
通过这种方法,您可以考虑使用{{1}}来分配一个干净的mbloc数组,或者甚至是vector<mbloc>
。