直接调用(虚拟)析构函数是否有效
Is it valid to directly call a (virtual) destructor?
在这个答案中,Ryan直接调用了虚拟析构函数。我已经在VS2010中测试了代码,它正确地调用了所有析构函数(使用日志记录语句进行了测试)。这样做真的有效吗?这种方法存在哪些问题、缺陷甚至优点?
我只能将其视为一种真正强制重置实际类型的方法,即使它们不覆盖虚拟reset
函数,因为它们至少必须在析构函数中进行清理。
另外,对析构函数的调用究竟会带来什么样的副作用?在这样的析构函数调用之后使用对象是未定义的行为吗?如果立即通过new (this) MyClass();
调用重新初始化它怎么办?
手动调用析构函数是一件完全有效的事情,无论它是否是虚拟的。你只需要确保它只为每个构造函数调用调用一次。
Is it undefined behaviour to use the object after such a destructor call?
是的。
What if one immediatly reinitializes it with a new (this) MyClass(); call?
仍然可怕地不确定。
不要手动销毁对象,除非您必须手动放置它,例如使用放置 new 或等效放置,并且绝对不要像这样重新初始化被破坏的对象并希望避免 UB。像std::vector
这样的类非常明确地使访问被销毁的对象成为UB,即使你随后在其位置创建一个新元素,它仍然是UB。
涉及一种且仅一种构造的有效使用示例:
typedef boost::aligned_storage<
sizeof(T), boost::alignement_of<T>::value>::type arena_type;
arena_type arena;
T* p = new (&arena) T();
p->~T();
// Don't touch p now
这在实现变体类型时很有用(警告:异常安全留给读者练习)。C++0x 无限制联合对类类型也有类似的用法。
请注意,对于类类型,如果未调用析构函数,则上述内容将是 UB。
只要您在预先分配的 POD 内存块之上调用放置新,那么释放调用任何析构函数(无论是否虚拟)都是完全有效的。
放置新的和显式的释放分配器调用将只调用引用区域中的构造函数和析构函数,因此内存分配有效地被排除在对象生命周期之外
相关文章:
- 析构函数是否会自动调用 delete[] C++?
- 循环中本地对象的析构函数是否保证在下一次迭代之前被调用?
- 文件流析构函数是否可以在C++中引发异常?
- 构造函数是否unique_ptr初始化原始指针unique_ptr析构函数是否也删除关联的原始指针?
- 析构函数是否可以在 const 对象上调用非 const 函数
- cpp 中的析构函数是否自动调用?即使析构函数没有提及非动态变量,它们也会被删除吗?
- 析构函数是否可以不调用特定字段的析构函数
- 动态分配(堆上)的对象的析构函数是否会在返回函数中自动调用
- 当类中存在虚函数时,隐式生成的析构函数是否也是虚拟的
- C++析构函数是否始终或仅在有时调用数据成员析构函数
- 根据C++标准,显式调用构造函数和析构函数是否安全
- std:map 析构函数是否调用键析构函数以及值析构函数?
- QNetworkAccessManager 析构函数是否中止当前请求
- 基类析构函数是否阻止生成移动构造函数
- 琐碎的析构函数是否会导致混叠
- 全局变量构造函数/析构函数是否需要线程保护
- 多态类的隐式析构函数是否可以成为虚拟的
- 默认的虚拟析构函数是否阻止编译器生成的移动操作
- 析构函数是否自动为成员变量解除分配堆内存
- 对象的析构函数是否释放用于创建对象的指针所指向的内存?