C++:如何结合指针为向量编写析构函数
c++: how to write a destructor for a vector combined with a pointer
我需要为学校的练习编写一个析构函数。我已经尝试为 A 类编写析构函数,这是正确还是错误的方式?
纸上练习
该练习说析构函数需要像这样开始:
A *pa = .......;
delete pa;
4个类的代码:
Class A
{
private:
vector <B*> b;
vector <C*> c;
public:
~A();
}
Class B
{
private:
vector <D*> d;
public:
~B();
}
Class C
{
private:
vector <D*> d;
public:
~C();
}
Class D
{
private:
vector <A*> a;
public:
~D();
}
我已经尝试为类 A
编写析构函数,这是正确的方法吗?
~A()
{
for (int i = 0; i < b.size(); i++)
{
B* pa = b[i];
delete pa;
}
for (int j = 0; j < c.size(); i++)
{
C* pa = c[i];
delete pa;
}
假设您不确定类 A
中两个vector
中的指针是否都不是NULL
,那么您可以执行以下操作:
~A()
{
for (int i = 0; i < b.size(); i++)
delete b[i];
b.clear(); // Making sure you do not access to deleted pointers
for (int i = 0; i < c.size(); i++)
delete c[i];
c.clear(); // Making sure you do not access to deleted pointers
}
我们还清除了向量,以确保无法访问已删除的点。或者,如果您仍然需要矢量的大小,您可以设置 b[i] = nullptr
和c[i] = nullptr
在两个循环中,而不清除向量。
这取决于构造函数的作用。
一般来说,构造函数建立一个类不变(所有成员函数都可以假定为真的一组属性),类外部使用的所有成员函数(例如公共成员,为派生类提供服务的受保护成员)保持该不变性。 析构函数执行与构造函数相反的操作 - 例如,如果构造函数显式分配某些资源,析构函数会释放它。
如果该不变量包括"b
的所有元素都被分配了运算符new
的结果",则析构函数必须使用(相应的运算符delete
释放这些元素,或者交给这样做的其他对象。 这通常被描述为所有权 - 类A
执行影响其他对象生存期的操作,因此必须清理。
如果该不变性包括"c
的所有元素要么是 NULL 指针,要么包含从其他地方提供的对象的地址",则析构函数不应释放这些对象。 例如,一些其他代码可能会提供指向 A
的成员函数的指针,并且该指针只是放在 c
中。 这假设您知道这些对象的生存期是在类A
之外管理的。
例如,考虑一个执行此操作的构造函数
A::A(int num_b, const std::vector<C *> &in_c) : b(0), c(in_c)
{
b.reserve(num_b); // so b doesn't keep on resizing itself below
for (int i = 0; i < num_b; ++i)
b.push_back(new B);
}
这样做的逻辑是,A
分配所有地址存储在b
中的对象,但只是从in_c
复制指针(这些指针可能在其他地方管理)。 所以类 A
负责 b
中对象的生存期,而不是c
中的对象的生存期。
然后我们假设,如果成员函数更改b
或c
,则在调用A
析构函数时仍然适用 - b
中的所有对象都由类 A
管理,但 c
中的对象则不然。 (换句话说,我们假设保持类不变性)。
那么析构函数可能看起来像
A::~A()
{
for (std::vector<B *>::iterator i = b.begin(), end = b.end();
i != end;
++i)
{
delete (*i);
}
}
注意我们不需要调整b
或c
的大小,因为std::vector
的析构函数负责清理自己。 但是,由于我们的类分配了对象并将其地址存储在b
中 - std::vector
对此一无所知 - 析构函数必须释放它们。
注意:上面的示例适用于所有版本的C++。 在 C++11 之后,析构函数中的代码可以简化,例如使用新的样式循环或auto
类型推导。
这取决于。如果A
拥有向量中的指针,因此负责销毁指向的对象,并且对象是使用 new
创建的,那么是的,析构函数看起来确实是正确的。
如果指向的对象不是用new
创建的,或者指针不是A
所有的,那么A
的析构函数不应该删除它们。
如果A
确实拥有指针,那么在类A
中分配对象将是糟糕的设计。但我认为,为了简单起见,这被排除在示例之外。
作为旁注:如果A
确实拥有指针并在析构函数中删除它们,则还应实现复制构造函数和复制赋值运算符,以便它们进行深层复制或使类不可复制。否则,如果您复制实例,您最终将出现未定义的行为。
但是正如您在 B 类和 C 类中看到的那样,我去了 D 类,但是如果我删除 D 会出错吗?
这样做完全没问题,除非...
。如果A
拥有指向B
和C
的指针,并且B
和C
拥有指向D
的指针,并且D
拥有指向A
的指针,以便它们都删除指向的对象,那么在类级别存在所有权循环。那还是没问题的,除非...
。有一个指针循环。例如,D
的一个实例(我们称之为 dee
)指向一个指向dee
的B
实例的A
实例,然后你有一个循环,你最终删除了一个对象,其析构函数已经启动,这会导致未定义的行为。
因此,如果这种指针循环是可能的,那么必须避免所有权循环。但是,如果不能有指针循环,那么所有权循环可能存在。
- 有没有一种"cleaner"的方法可以在指向基的指针向量中找到派生类的第一个实例?
- 如何更改唯一指针向量的可见性
- 如何在基类指针向量的元素上应用重载的多态函数
- C++:添加新结构时,结构指针向量中的所有元素都会更新
- 包含指向其他结构的指针向量的结构
- 如何将子类作为函数的参数传递给期望基类,然后将该对象传递到指向这些抽象类对象的指针向量中?
- 如何将字符串指针数组转换为字符串类型的智能指针向量?
- 初始化可变数据结构中的共享指针向量
- 指向具有 decltype 的函数的指针向量
- push_back指向指针向量的指针
- 使用指针向量(带代码)C++(以及对其使用的便利性的怀疑)时出现问题
- 我可以做些什么来改进指针向量中的此搜索?
- 指向指针排序向量的指针向量的 C++ 向量
- 初始化用户定义类的指针向量
- 函数无法识别我在C++传递节点指针向量?
- 如何声明指向类对象的指针向量?
- 指向结构的指针向量的元素具有相同的地址
- 删除指向抽象类的指针向量
- 当我返回指向结构的指针向量时出现段错误
- 用基于范围的for循环填充指针向量