如何手动删除类的实例?
示例:
#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 << "\n\n";
return 0;
}
答案 0 :(得分:8)
在不知道用例或您想解决的实际问题的情况下(请阅读the XY problem,您的问题就是一个很好的例子)最简单的方法就是重新分配:
swiss
这当然可能要求您实现赋值运算符,但是遵循rules of three or five无论如何都应该这样做(但如果您遵循the rule of zero则不需要赋值运算符。)
如果您明确要销毁当前的Cheese* swiss = new Cheese("Jarlsberg", 4.99);
...
delete swiss;
swiss = new Cheese("Gruyère",5.99);
对象, 也可以使用指针:
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
但是指针是你应该避免的一堆蠕虫,并且在现代C ++中并不需要太多。但是如果你想要多态性,则需要指针(或引用)。然后你可以有一个指向实际实例的基类的指针,像虚函数这样的东西将按预期工作。
另外,根据您的情况我们仍然不知道,您当然可以使用范围界定:
jarlsberg
虽然像这样的阴影变量名称有效,但是你应该避免这是一个坏习惯,因为它会给代码的读者增加混乱。另一方面,即使使用作用域,也不会阻止您使用任何(有效)变量名称,因此可以将外部作用域实例gruyere
和内部作用域实例gruyere
命名为{{然后,对象将在范围的末尾被破坏,就像任何其他嵌套范围变量将被破坏并“消失”一样。
答案 1 :(得分:4)
可以使用作用域来定义另一个类的实例。
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.
必须始终手动删除动态分配的内存。
答案 2 :(得分:2)
在极少数情况下您需要这样做。但是,您可能遇到的是创建抽象数据类型时。
例如,如果您正在制作变体类型,则可能需要设置对齐的数据类型,然后手动放置新的和删除。
typename std::aligned_union<0, FirstType, RestTypes...>::type m_buffer;
为了生存:
new (&m_buffer) AssignType(forward<T>(x));
要清除:
(HeldType*)(&m_buffer)->~HeldType();
然而,如众多其他帖子所述。如果你正常编程,那么你不必担心手动调用dtors。如果它在堆栈上,那么它就会被清理干净。如果它在堆上,那么delete
将为您处理它。您想要执行此操作的唯一时间是您手动控制对象生命周期,并且您要执行此操作的主要原因是您实现抽象数据类型时。
答案 3 :(得分:1)
一般规则 一旦超出范围,本地创建的实例将自动删除/处理。 需要手动删除动态创建的实例(动态内存分配),如下所示:
删除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 << "\n\n";
return 0;
}
答案 4 :(得分:0)
C ++的黑暗面带来了一种技术,可以准确地执行您在原始帖子中描述的内容。我不知道你为什么要这样做 - 也许实现一个赋值运算符似乎很乏味。也许你有一个病态的愿望,为你的程序做一些不自然的事情。我可以向你保证,没有&#34;正常&#34;人会考虑使用我在下面透露的代码,至少在别人看的时候不会。那我为什么要把它放在这里呢?
因为我很伤心。
我呼吁社区维基的力量保护我免受冲击!
#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';
}
答案 5 :(得分:0)
如果由于某种原因您无法使用赋值运算符,则可以使用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);
只要您没有存储可选项,您可以依赖编译器优化额外的内部布尔值。