如何手动删除类的实例
How do I manually delete an instance of a class?
如何手动删除类的实例?
示例:
#include <iostream>
#include <cstring>
class Cheese {
private:
string brand;
float cost;
public:
Cheese(); // Default constructor
Cheese(string brand, float cost); // Parametrized constructor
Cheese(const Cheese & rhs); // Copy construtor
~Cheese(); // Destructor
// etc... other useful stuff follows
}
int main() {
Cheese cheddar("Cabot Clothbound", 8.99);
Cheese swiss("Jarlsberg", 4.99);
whack swiss;
// fairly certain that "whack" is not a keyword,
// but I am trying to make a point. Trash this instance!
Cheese swiss("Gruyère",5.99);
// re-instantiate swiss
cout << "nn";
return 0;
}
在不知道用例或您想要解决的实际问题的情况下(请阅读XY问题,您的问题就是一个很好的例子),最简单的方法就是重新分配:
Cheese swiss("Jarlsberg", 4.99);
...
swiss = Cheese("Gruyère",5.99);
当然,这可能需要实现赋值运算符,但按照三或五的规则,无论如何都应该这样做(但如果按照零的规则,则不需要赋值运算符)。
如果您明确希望销毁当前swiss
对象:,则也可以使用指针
Cheese* swiss = new Cheese("Jarlsberg", 4.99);
...
delete swiss;
swiss = new Cheese("Gruyère",5.99);
但是指针是一个你应该避免的蠕虫,在现代C++中并不需要太多。但是,如果您想要多态性,则需要指针(或引用)。然后,您可以有一个指向基类的指针,指向实际实例,像虚拟函数这样的东西将按预期工作。
此外,根据您的情况,我们仍然一无所知,您当然可以使用范围界定:
Cheese swiss("Jarlsberg", 4.99);
...
{
Cheese swiss("Gruyère",5.99);
// In here the swiss cheese is a Gruyère
...
}
// Out here the swiss cheese is a Jarlsberg
虽然像这样隐藏变量名是有效的,但这是一个坏习惯,您应该避免,因为它会给代码的读者带来困惑。另一方面,即使在使用作用域时,也不会阻止您使用所需的任何(有效)变量名,因此您可以将外部作用域实例命名为jarlsberg
,将内部作用域实例名称命名为gruyere
,然后gruyere
对象将在作用域的末尾被销毁,就像任何其他嵌套作用域变量将被销毁并"消失"一样。
可以使用作用域来定义类的另一个实例。
Cheese swiss("Toe", 3.14)
{
Cheese swiss("Ear", 15.9);
}
一般来说,当本地声明的实例超出范围时,它们会自行销毁。
如果你真的满足了销毁奶酪的需求,那么你需要动态地分配它。
Cheese *swiss = new Cheese("toe", 3);
// do something with swiss.
delete swiss; // throw it away.
swiss = new Cheese("Ear", 7);
// do something with swiss.
delete swiss; // throw it away.
必须始终手动删除动态分配的内存。
很少有实例需要这样做。但在创建抽象数据类型时可能会遇到一个问题。
例如,如果您正在制作一个变体类型,您可能需要设置一个对齐的数据类型,然后手动放置新的数据类型并删除。
typename std::aligned_union<0, FirstType, RestTypes...>::type m_buffer;
生动:
new (&m_buffer) AssignType(forward<T>(x));
要清除:
(HeldType*)(&m_buffer)->~HeldType();
然而,正如在许多其他帖子中提到的那样。如果您正在正常编程,那么您不需要担心手动调用dtor。如果它在堆栈上,那么它会为您清理。如果它在堆上,那么delete
将为您处理它。唯一想这样做的时候是手动控制对象的生存期,而想要这样做的主要原因是在实现抽象数据类型时。
一般规则本地创建的实例一旦超出范围就会自动删除/处理。动态创建的实例(动态内存分配)需要手动删除,如下所示:
删除实例名称
- 备注:不要在~cheese()(~destructor)中包含delete instance_name语句,否则它将进入循环并崩溃
在上面的情况下,如果您想手动删除实例,建议使用DMA:
int main() {
Cheese cheddar("Cabot Clothbound", 8.99);
Cheese* swiss = new swiss("Jarlsberg", 4.99);
delete swiss;
Cheese swiss("Gruyère",5.99);
// re-instantiate swiss
cout << "nn";
return 0;
}
C++的黑暗面提出了一种技术,可以准确地执行您在原始文章中描述的内容。我不知道你为什么要这样做——也许实现一个赋值操作符看起来很乏味。也许你有一种病态的欲望,想对你的程序做一些不自然的事情。我可以向你保证,没有一个"正常"的人会考虑使用我在下面透露的代码,至少在其他人观看的时候不会。那我为什么要把这个放在这里?
因为我是虐待狂。
我呼吁社区维基的力量来保护我免受攻击!
#include <iostream>
#include <string>
#include <new>
template <typename T, typename ...As>
inline void Reconstruct(T &ojt, const As&... ctor_args) {
// Explicitly call the destructor, to destroy the object
// without doing anything to its memory allocation.
ojt.~T();
// Use Placement new to call a constructor.
// Instead of allocating memory somewhere for a new object,
// this specifies where the new object will be constructed --
// given here as the location of the object's previous
// incarnation.
// Also pass any arguments to the constructor. I forced
// these arguments to be const references in order to
// avoid extra copying, so "move" construction won't work
// and steps might need to be taken to accommodate other,
// more unusual constructors.
new(&ojt) T(ctor_args...);
}
class Cheese {
std::string brand;
float cost;
public:
Cheese() : cost(0) {}
Cheese(std::string brand, float cost) : brand(brand), cost(cost) {}
Cheese(const Cheese & rhs) = default;
~Cheese() = default;
friend std::ostream& operator << (std::ostream& os, const Cheese& chz) {
return os << "[brand:"" << chz.brand << "" cost:" << chz.cost << ']';
}
};
int main() {
Cheese cheese, fromage;
std::cout << "cheese = " << cheese << 'n';
Reconstruct(cheese, "Cabot Clothbound", 8.99f);
std::cout << "cheese = " << cheese << 'n';
Reconstruct(fromage, cheese);
std::cout << "fromage = " << fromage << 'n';
Reconstruct(cheese, "Jarlsberg", 4.99f);
std::cout << "cheese = " << cheese << 'n';
}
如果由于任何原因不能使用赋值运算符,则可以使用optional
。
std::experimental::optional<Cheese> swiss(std::experimental::in_place, "Jarlsberg", 4.99);
swiss = std::experimental::nullopt; // Calls Cheese::~Cheese internally
// re-instantiate swiss
swiss.emplace("Gruyère",5.99);
只要不存储可选项,就可以依靠编译器来优化多余的内部bool。
- 从DLL中删除类的实例
- 删除功能不适用于串行通信后多个循环中的多个实例
- 从函数中全局删除并重新实例化数组结构,而无需在编译时知道数组的大小
- 使用部分模板实例化删除限定符
- 清除具有已删除赋值运算符的成员的类实例
- 为什么自删除的全局 Vulkan 实例仅在添加层时才导致段错误?
- 如何在C++中将类的实例完全重新分配给同一类的另一个实例(然后删除原始对象)?
- 是否可以实例化具有已删除构造函数和析构函数的非聚合类?
- 当指针指向的对象被另一个类的实例删除时,重新分配指针
- 如何创建一个结构的实例,当它不在范围内时,该实例将不会被删除
- 如何计算实例数组中未删除的实例
- 完全删除 QApplication 实例并在另一个线程中重新创建它
- 有条件地实例化具有删除默认构造函数的类
- 如何在返回一次数据后从类实例中删除数据
- 从字符串中删除字符的第一个和最后一个实例
- C++不允许堆栈实例,但允许新的删除
- 删除C++中动态分配的类实例
- 返回实例导致"尝试引用已删除的函数"错误
- 应由库或客户端代码删除已加载库中的对象实例
- 类的静态实例无法在程序退出时正确处理资源删除