使用-O3使用g ++进行编译时,C ++程序中的分段错误

时间:2014-09-16 19:14:58

标签: c++ segmentation-fault g++

当我使用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();
    }
}

2 个答案:

答案 0 :(得分:2)

你似乎试图在这里做一个基于内存池的分配器,这一般不是一个坏主意。 (但实现可能会使用很多改进。)

你遇到的问题是对齐。 int可能是4字节对齐的。 double可能是8字节对齐的。

malloc返回的地址始终适合任何类型的具有基本对齐要求的对象 - 因此它始终与intdouble完全一致。当您尝试分配奇数个int时会发生此问题。假设malloc返回地址0x3000并且您分配了五个int,那么curMemPos2的地址变为0x3014,然后您尝试分配五个double 1}} s - 但0x3014不是double的有效地址,因为它不是8字节对齐的。

答案 1 :(得分:1)

它没有使用优化,而它没有工作,这表明你的代码中有一些未定义的行为,在某些情况下(un)幸运的是。

你有几个候选人:

  • 如果两个不同类型的指针(例如int *wordsdouble *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>