[编辑以包括最小的可重现示例]
我正在实现一个类 (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";
}
在ringBuffer类中使用calloc(将所有内容初始化为0)而不是malloc解决了我的问题。我仍然有兴趣知道是否有人有可以在 kClause 类中实现的可能解决方案。