我正在尝试实现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()
接受一个参数,即应该删除元素的索引。所以我创建了一个新数组,将所有内容复制到erasion-index,跳过索引,然后复制其余内容。然后我删除旧数组并为变量分配新数组。
我在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));
}
咨询调试器后,我发现了以下内容:
data[0]
被破坏后 - o
和l
变量获得随机值,而ptr
仍然指向正确的字符串。ptr
现在变为NULL
,data[1]
现在具有随机的o
和l
值。之后delete []
被调用,这不会引起错误,因为我用分配的内存做了一些狂野的竞技场。
我在哪里管理不善?
doubleSize
分配新缓冲区,但不更新capacity
成员。 Oncelength
已经过了capacity
,你甚至都不会再发现溢出了。最终,你会溢出真实。
虽然您正在使用erase
进行擦除,但这会减小向量的大小,但它不会减少您的length
变量。