当使用模板类创建自定义向量时,我应该如何处理析构函数?

Use*_*ser 2 c++ containers destructor vector rule-of-five

我尝试使用模板类创建自定义 Vector 类。

我希望我可以将我的放入变量Vector<int>Vector<Vector<int>>。至少那是我所希望的......但它在析构函数代码处不断崩溃。

这是我的代码。

#include <iostream>
#include <string>

template <typename T>
class Vector {

    T* data;
    int capacity;
    int length;

public:

    typedef T value_type;

    Vector() {}

    Vector(int n) : data(new T[n]), capacity(n), length(0) {}

    void push_back(T input) { 
        data[length++] = input;
    }

    T operator[](int i) { return data[i]; }

    virtual ~Vector() { if (data) delete[] data; }
};

int main() {
    Vector<Vector<int>> v(3);
    Vector<int> vv(4);
    v.push_back(vv);
}
Run Code Online (Sandbox Code Playgroud)

所以我想,也许我应该使用复制构造函数,因为问题似乎是v之前被删除了vv。好吧,如果我只是注释掉析构函数代码,它就会起作用,但这对我来说似乎不对......

所以我做了一个自定义的复制构造函数,如下所示:

Vector(const T& other) { 

}
Run Code Online (Sandbox Code Playgroud)

但它给了我一个错误,说“不明确的重载”......回想起来,当然这是错误的,因为TofdataTof不同other......

我怎样才能让我的定制Vector课程发挥作用?(即我希望Push_back按我的预期工作......)

ein*_*ica 6

一般问题

在类设计中,特别是涉及内存/资源分配时,通常需要遵循“五规则”(在 C++11 之前曾是“三规则”):

如果您实施以下任何一项:

  • 一个析构函数
  • 复制/移动赋值运算符
  • 复制/移动构造函数

那么你可能需要实现所有这些。

原因是它们中的每一个都可能需要一些资源管理逻辑,超出了语言默认提供的逻辑。

对于您的类,这五个方法的签名将是:

方法 签名
复制构造函数 Vector(const Vector&)
移动构造函数 Vector(Vector&&)
复制赋值运算符 Vector& operator=(const Vector&)
移动赋值运算符 Vector& operator=(Vector&&)
析构函数 ~Vector()或者 virtual ~Vector()

您的具体班级

根据您的具体情况,存在几个具体问题:

  • 正如 @UnholySheep 所建议的,您错误地声明了复制构造函数。
  • 您实现了默认构造函数;但是 - 它不分配任何东西,也不初始化任何东西!该data指针保存任意垃圾,当您尝试释放它时,很可能会发生不好的事情。
  • 您正在执行大量T值的复制,对于外部向量来说,这些值将是Vector<int>值 - 这可能会变得昂贵。
  • 即使您修复了上述问题,您仍然应该实现“五规则”中缺少的方法。


Bot*_*tje 5

您的默认构造函数使对象完全未初始化。

考虑一下当你声明一个时会发生什么

Vector<int> foo;
Run Code Online (Sandbox Code Playgroud)

foo本质上获得一个随机内存地址data,一个随机的lengthcapacity。如果你释放它,它会发出烟花。

也许您通过始终创建具有预定义大小的矢量来回避这个问题。幸运的是,尝试创建/销毁 aVector<Vector<int>>会使这一点暴露出来,因为Vector<int>[]容器内部仍然包含这些滴答作响的定时炸弹。