我正在尝试实现Vector类。首先,我的Vector尚不支持泛型,仅支持我的Thing
类。
Vector类应支持:empty(),push_back(),erase()和下标运算符。如果需要,它还应该相应地调整大小。
我的Vector实现:
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] = '\0';
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()
方法中做了非常相似的事情,似乎工作得很好(检查valgrind)。
我遇到的问题是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));
}
咨询调试器后,我发现了以下内容:
first for循环效果很好。
第二个循环:在第二次迭代之后,在赋值之后-data[0]
被破坏-o
和l
变量获得随机值,而ptr
仍指向正确的字符串。
在完成第二个循环的最后一次迭代后,ptr
现在变为NULL
,而data[1]
现在具有随机的o
和l
值。 / p>
然后调用delete []
,因为我对分配的内存进行了一些狂放的牛仔竞技表演,因此会意外触发错误。
我在哪里管理内存不足?
答案 0 :(得分:5)
doubleSize
分配新的缓冲区,但不更新capacity
成员。一旦length
经过capacity
,您甚至不再检测到溢出。最终,您将真正溢出。
尽管您正在使用erase
进行擦除,但这会减小向量的大小,但不会减少length
变量。