实施C 模板列表类的有效初始化

Implementing efficient initialization of C++ Template List classes

本文关键字:有效 初始化 列表 实施      更新时间:2023-10-16

用于编写模板列表类,相当于向量(纯粹是设计练习(,我正在尝试找出要高效的事情。

如果写信:

v = new T[size];

然后,编译器将调用T的构造函数,对吗?T()

因此,在下面的课程中:

v = (T*) new char[sizeof(T) * size]

这似乎很容易。但是,在破坏者中,如何仅删除被初始化的删除?在下一类中,只有第一个"使用"元素被初始化。

另外,在复制构造函数中,如何仅对使用的元素调用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
    }
};

要像 std::vector一样,您需要使用"放置新"并明确调用破坏者。

#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]);
}

注意以上复制构造函数并不是例外安全。尝试这样做。

首先,只需使用 std::vector<T>而不是自己重新实现。

您在这里寻找的是放置新显式驱动器调用。通常,每个new都应与delete配对,每个位置都应与明确的destructor调用配对。

回答您的特定问题:

然而,在灾难中,如何仅删除已被初始化的删除?

明确调用其破坏者,然后 char[]正确分配了原始CC_11,它将(正确(自动调用任何T destructors。

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]);

对于复制构造函数,您可以尝试此代码:

#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);
    }