对于编写模板列表类,相当于矢量(纯粹作为设计练习),我试图找出有效的方法。
如果有人写道:
v = new T[size];
然后编译器会调用T
的构造函数,对吧? T()
。
所以在下面的课程中:
v = (T*) new char[sizeof(T) * size]
这似乎很容易。但是,在析构函数中,如何删除已初始化的那些?在下面的类中,只初始化了第一个“used”元素。
另外,在复制构造函数中,如何有效地仅为使用过的元素调用T
的复制构造函数?
如果我初步确定了昂贵的方式,那就有效:
v = new T[size];
for (int i = 0; i < used; i++)
v[i] = orig.v[i];
但这需要v
已经使用T()
进行了宣传。有什么更好的方法?
课程如下:
#include <cstdint>
template<typename T>
class List {
private:
uint32_t used;
uint32_t capacity;
T* v;
public:
List(uint32_t cap) : used(0), capacity(cap), v((T*)new char[sizeof(T)*capacity]) {}
~List() {
delete [] v; // no
}
List(const List& orig) : used(orig.used), capacity(orig.capacity), v((T*) new char[sizeof(T)*capacity]) {
// now copy only the used ones
for (int i = 0; i < used; i++)
v[i] = orig.v[i]; // no, operator = will call destructor on v[i], but it is uninitialized
}
};
答案 0 :(得分:1)
与std::vector
类似,您需要使用“placement new”并明确调用析构函数。
#include <new>
~List() {
while (used) {
--used;
v[used]->~T();
}
delete[] reinterpret_cast<char*>(v);
}
List(const List& orig) : used(orig.used), capacity(orig.capacity),
v(reinterpret_cast<T*>(new char[sizeof(T)*capacity])) {
// now copy only the used ones
for (int i = 0; i < used; i++)
new(v+i) T(orig.v[i]);
}
请注意,上面的复制构造函数不是异常安全的。尽量做到这一点。
答案 1 :(得分:0)
首先,只需使用std::vector<T>
而不是自己重新实现。
您在这里寻找的是贴装新和显式析构函数调用。通常情况下,每个new
应与delete
配对,每个展示位置都应与显式析构函数调用配对。
回答您的具体问题:
但是,在析构函数中,如何只删除已经初始化的那些?
明确地调用他们的析构函数,然后正确delete[]
原始char[]
分配,这将(正确)不自动调用任何T
析构函数。
for (uint32_t i = 0; i < used; ++i) {
v[i]->~T();
}
delete [] reinterpret_cast<char *>(v);
另外,在复制构造函数中,如何有效地仅为使用过的元素调用
T
的复制构造函数?
你需要在这里放置新的。您的行v[i] = orig.v[i];
会导致未定义的行为,因为尚未构建v[i]
。
安置新对象(在使用之前应该对每个v[i]
执行此操作):
new(reinterpret_cast<char *>(v + i)) T(orig.v[i]);
答案 2 :(得分:0)
对于复制构造函数,您可以尝试以下代码:
#include <cstring>
List(const List& orig) : used(orig.used), capacity(orig.capacity), v((T*) new char[sizeof(T) * capacity]) {
// now copy only the used ones
memcpy(v, orig.v, sizeof(T)*capacity);
}
或
List(const List& orig) : used(orig.used), capacity(orig.capacity), v((T*) new char[sizeof(T) * capacity]) {
// now copy only the used ones
memcpy_s(v, capacity, orig.v, sizeof(T)*capacity);
}