free():实现矢量擦除()时的指针无效

free(): invalid pointer when implementing erase() of vector

本文关键字:无效 擦除 指针 实现 free      更新时间:2023-10-16

我正在尝试实现Vector类。首先,我的 Vector 还不支持泛型,只支持我的Thing类。

Vector 类应该支持:empty()、push_back()、erase() 和下标运算符。如果需要,它还应相应地调整大小。

我的矢量实现:

class Vect {
public:
Vect() {
length = 0;
capacity = 3;
charCnt = 0;
data = new Thing[capacity];
}
~Vect() {
delete[] data;
}
bool empty() const {
return length == 0;
}
void push_back(const char *str) {
if(length + 1 == capacity)
doubleSize();
data[length++] = Thing(str);
charCnt += strlen(str);
}
bool erase(size_t at) {
if(at >= length)
return false;
auto newData = new Thing[capacity];
size_t newIndex = 0;
for(size_t i = 0; i < at; i++)
newData[newIndex++] = data[i];
for(size_t i = at + 1; i < length; i++)
newData[newIndex++] = data[i];
//free(): invalid pointer
delete[] data;
data = newData;
return true;
}
const char* operator[](unsigned int index) {
return data[index].getStr();
}
char* toString() {
auto result = make_shared<char *>(new char[charCnt + 1]);
size_t resultIndex = 0;
for(size_t dataIndex = 0; dataIndex < length; dataIndex++) {
auto patchOffset = data[dataIndex].getO();
auto patchLength = data[dataIndex].getL();
for(size_t patchIndex = patchOffset; patchIndex < patchLength; patchIndex++)
(*result.get())[resultIndex++] = data[dataIndex].getStr()[patchIndex];
}
(*result.get())[resultIndex] = '';
return *result.get();
}
private:
size_t length, capacity, charCnt;
Thing *data;
void doubleSize() {
size_t newCapacity = capacity*2;
auto newData = new Thing[newCapacity];
for(size_t i = 0; i < length; i++) {
newData[i] = data[i];
}
//this works
delete[] data;
data = newData;
}
};

当我尝试实施erase()时,我遇到了问题。我的实现很简单:erase()接受一个参数,即应该删除元素的索引。所以我创建了一个新数组,将所有内容复制到擦除索引,跳过索引,然后复制其余内容。然后我删除旧数组并将新数组分配给变量。

我在doubleSize()方法中做了非常相似的事情,似乎工作正常(检查瓦尔格林德)。

我遇到的问题是delete[]不适用于data

我使用的测试环境:

class Thing {
public:
Thing() {
o = 0;
l = 0;
ptr = nullptr;
}
explicit Thing(const char *str) {
ptr = str;
o = 0;
l = strlen(str);
}
Thing(const Thing &other) {
this->o = other.o;
this->l = other.l;
this->ptr = other.ptr;
}
friend void swap(Thing &first, Thing &other) {
using std::swap;
swap(first.o, other.o);
swap(first.l, other.l);
swap(first.ptr, other.ptr);
}
Thing& operator=(Thing other) {
swap(*this, other);
return *this;
}
Thing(Thing &&other) noexcept: Thing() {
swap(*this, other);
}
size_t getO() const {
return o;
}
size_t getL() const {
return l;
}
const char* getStr() const {
return ptr;
}
private:
size_t o, l;
const char *ptr;
};
//class Vect...
int main() {
Vect s; char tmpStr[100];
assert(s.empty());
s.push_back("hello ");
s.push_back("world");
s.push_back("!");
s.push_back(" this ");
s.push_back("is ");
s.push_back("me!");
strncpy(tmpStr, "hello world! this is me!", sizeof(tmpStr));
assert(stringMatch(s.toString(), tmpStr));
s.erase(2);
strncpy(tmpStr, "hello world this is me!", sizeof(tmpStr));
assert(stringMatch(s.toString(), tmpStr));
}

在咨询调试器后,我发现了以下内容:

  1. 就内容而言,第一个循环工作正常。

  2. 第二次
  3. 循环:在第二次迭代之后,在赋值之后 -data[0]被损坏 -ol变量获得随机值,而ptr仍然指向正确的字符串。

  4. 完成第二个循环的最后一次迭代后,ptr现在变为NULLdata[1]现在具有随机ol值。

之后delete []被调用,这将毫不奇怪地触发错误,因为我用分配的内存做了一些狂野的牛仔竞技表演。

我在哪里管理我的记忆不善?

doubleSize分配新的缓冲区,但不更新capacity成员。一旦length过了capacity,你甚至不再检测到溢出。最终,你会真正溢出。


虽然您使用erase擦除,这会减小矢量的大小,但不会减少length变量。