C++ 在复制赋值运算符中释放内存

问题描述 投票:0回答:1

[编辑以包括最小的可重现示例]

我正在实现一个类 (kClause),它是一个指向具有嵌入函数的数组的指针(从概念上讲,非常像字符串,但具有 32 位而不是 8 位“字符”)。该类的每个实例可能有一个不同长度的关联数组。

在复制赋值运算符中,我需要重新分配内存(而不仅仅是交换),因为初始内存分配可能是针对不同长度的数组(较短的长度会导致灾难性问题)。然而,释放内存会导致错误,因为在初始分配之前调用复制赋值运算符。

在示例中,您可以看到这是如何发生的。模板类ringBuffer 使用malloc 为kClause 保留内存,但malloc 不会调用kClause 构造函数。因此,当ringBuffer.push()调用复制赋值运算符free(Arr)时,会在未分配的内存上调用,从而导致错误。

也许在ringBuffer中使用new而不是malloc是一个解决方案——但我宁愿在kClause类中解决这个问题。我知道没有办法测试 this->Arr 是否指向已分配的内存...因此,有什么建议如何在这两种情况下使其工作(情况是: this->Arr 指向需要释放的已分配内存,或者它没有)或者也许是一个聪明的解决方法?


//save some keystrokes:
#define int32 uint32_t
#define int64 uint64_t

using namespace std;

class kClause {
    int32 k; //dimension
    int32* Arr;

    void init(int32 dimension) {
        k = dimension;
        Arr = (int32*)calloc(k, sizeof(*Arr));
        assert(Arr != 0);
    }
public:
    kClause() { //default cstor
        init(4);
    }
    kClause(int32 dimension) {
        init(dimension);
    }
    kClause(const kClause& other) { //copy constructor
        k = other.k;
        Arr = (int32*)calloc(k, sizeof(*Arr));
        assert(Arr != 0);
        memcpy(Arr, other.Arr, k * sizeof(*Arr));
    }
    kClause& operator=(const kClause& rhs) { //copy assignment
        //check for self assignment:
        if (this == &rhs) return *this;

        free(Arr); //free the old data: Exception Thrown Here, but Memory leak without this!

        //now the same as the copy constructor
        k = rhs.k;
        Arr = (int32*)calloc(k, sizeof(*Arr));
        assert(Arr != 0);
        memcpy(Arr, rhs.Arr, k * sizeof(*Arr));
        return *this;
    }
    ~kClause() { free(Arr); } //destructor

    //useful functions go here
};

template <class T> class ringBuffer {
    //a dynamically rescaling ring buffer
    int32 size;
    T* Arr;
    int32 first;//first used index
    int32 next;//next open index... When next == first the array is empty

    void resize() {
        T* newArr = (T*)malloc((int64)size * 2 * sizeof(*Arr));
        assert(newArr != 0);
        memcpy(newArr, Arr, size * sizeof(T));
        free(Arr);
        Arr = newArr;
        //now the indices between 0 and next - 1 are in the wrong place if they wrap around.
        if (next < first) {
            memcpy(Arr + size, Arr, next * sizeof(*Arr)); //i.e if next is 5 then 0 thru four get moved to size thru size + 5.
            //Now everything is in the right place, so we can correct the pointers:
            next += size;
        }
        size *= 2;
    }

public:

    void init(int32 sz) {
        size = sz;
        Arr = (T*)malloc(size * sizeof(*Arr));
        assert(Arr != 0);
        first = 0;
        next = 0;
    }
    ringBuffer(int32 sz) { //constructor
        init(sz);
    }
    void push(T in) {
        if (numElements() >= size - 1) {
            resize();
        }
        if (next == size) {
            next = 0;
        }
        Arr[next] = in;
        next++;
        if (next == size) next = 0;
    }
    int32 numElements() {
        if (next >= first) return next - first;
        return (size - first) + next;
    }
};


int main() {
    ringBuffer<kClause> rBuff(16);
    kClause kC;
    rBuff.push(kC);
    cout << "There are " << rBuff.numElements() << " kClauses in the ringBuffer.\n";
}

c++ malloc calloc copy-assignment
1个回答
0
投票

在ringBuffer类中使用calloc(将所有内容初始化为0)而不是malloc解决了我的问题。我仍然有兴趣知道是否有人有可以在 kClause 类中实现的可能解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.