C++ 如何手动删除类的实例?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36192499/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 14:35:43  来源:igfitidea点击:

How do I manually delete an instance of a class?

c++classinstancedestructorkill

提问by kmiklas

How do I manually delete an instance of a class?

如何手动删除类的实例?

Example:

例子:

#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;
}

回答by Some programmer dude

Without knowing the use-case or the actual problem you want to solve (please read about the XY problem, your question is a good example of it) the simplest way is just reassigning:

在不知道用例或您想要解决的实际问题的情况下(请阅读XY 问题,您的问题就是一个很好的例子),最简单的方法就是重新分配:

Cheese swiss("Jarlsberg", 4.99);
...
swiss = Cheese("Gruyère",5.99);

That might of course require you to implement an assignment operator, but following the rules of three or fiveyou should do that anyway (but the assignment operator is not needed if you follow the rule of zero).

这当然可能需要您实现赋值运算符,但遵循三或五规则,无论如何您都应该这样做(但如果您遵循零规则,则不需要赋值运算符)。

You couldalso use pointers, if you explicitly want to destroy the current swissobject:

如果您明确想要销毁当前对象,您可以使用指针swiss

Cheese* swiss = new Cheese("Jarlsberg", 4.99);
...
delete swiss;
swiss = new Cheese("Gruyère",5.99);

But pointers is a can of worms that you should avoid, and don't really need much in modern C++. But pointers (or references) are needed if you want polymorphism. Then you could have a pointer to the base class pointing to the actual instance, and things like virtual functions will work as expected.

但是指针是一种你应该避免的蠕虫,在现代 C++ 中并不真正需要它。但是如果您想要多态性,则需要指针(或引用)。然后你可以有一个指向实际实例的基类的指针,虚拟函数之类的东西将按预期工作。

Also, and depending on your situation which we still know nothing about, you could of course use scoping:

此外,根据我们仍然一无所知的情况,您当然可以使用范围界定:

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

Though shadowing variable names like this works, it's a bad habit that you should avoid as it adds confusion for readers of the code. On the other hand, even when using scopes nothing stops you from using any (valid) variable name you want, so you could name the outer scope instance jarlsbergand the inner scope instance gruyere, the gruyereobject would then be destructed at the end of the scope just like any other nested-scope variable would be destructed and "disappear".

虽然像这样隐藏变量名是有效的,但这是一个你应该避免的坏习惯,因为它会给代码的读者增加混淆。另一方面,即使使用范围,也不会阻止您使用任何(有效)变量名称,因此您可以命名外部范围实例jarlsberg和内部范围实例gruyeregruyere然后该对象将在范围结束时被销毁像任何其他嵌套范围变量一样会被破坏并“消失”。

回答by EvilTeach

One can use scoping to allow you to define another instance of a class.

可以使用作用域来定义类的另一个实例。

Cheese swiss("Toe", 3.14)

{
    Cheese swiss("Ear", 15.9);
}

As a general rule locally declared instances will destroy themselves when they go out of scope.

作为一般规则,本地声明的实例在超出范围时会自行销毁。

If you really feed the need to destroy cheese, then you need to dynamically allocate it instead.

如果你真的满足销毁奶酪的需求,那么你需要动态分配它。

  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.

Dynamically allocated memory must always be manually deleted.

必须始终手动删除动态分配的内存。

回答by OmnipotentEntity

There are precious few instances where you would need to do this. But one that you might run into is when creating an abstract data type.

在极少数情况下您需要这样做。但您可能会遇到的一个问题是在创建抽象数据类型时。

For instance, if you're making a variant type you'll probably want to set up an aligned data type and then manually placement new and delete.

例如,如果您正在制作一个变体类型,您可能需要设置一个对齐的数据类型,然后手动放置新的和删除的。

typename std::aligned_union<0, FirstType, RestTypes...>::type m_buffer;

To vivify:

活起来:

new (&m_buffer) AssignType(forward<T>(x));

To clear:

清除:

(HeldType*)(&m_buffer)->~HeldType();

However, as mentioned in the numerous other posts. If you're programming normally, then you don't need to worry about manually calling dtors. If it's on the stack then it's cleaned up for you. If it's on the heap then deletewill take care of it for you. The only time where you want to do this is where you're manually taking control over object lifetimes, and the main reason why you'd want to do this is when you're implementing an abstract data type.

但是,正如许多其他帖子中所述。如果你正常编程,那么你就不用担心手动调用dtors了。如果它在堆栈上,那么它已经为你清理干净了。如果它在堆上,那么delete会为你处理它。唯一想要这样做的地方是您手动控制对象生命周期,而您想要这样做的主要原因是在实现抽象数据类型时。

回答by Christopher Oicles

The Dark Side of C++ posesses a technique for performing exactly what you describe in the original post. I don't know why you want to do this -- maybe implementing an assignment operator seems tedious. Maybe you have a morbid desire to do something unnatural to your program. I can assure you that no "normal" person would consider using the code I reveal below, at least not when others are watching. So why am I putting this here?

C++ 的阴暗面提供了一种技术,可以准确地执行您在原始帖子中描述的内容。我不知道你为什么要这样做——也许实现赋值运算符似乎很乏味。也许你有一种病态的愿望,想要对你的程序做一些不自然的事情。我可以向你保证,没有“正常”的人会考虑使用我在下面展示的代码,至少在其他人观看时不会。那我为什么把这个放在这里?

Because I'm sadistic.

因为我是虐待狂。

I call upon the power of Community Wiki to shield me from the onslaught!

我呼吁社区维基的力量保护我免受冲击!

#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';
}

回答by sbabbi

If for whatever reason you can not use the assignment operator, you can use an optional.

如果由于某种原因不能使用赋值运算符,则可以使用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);

As long as you are not storing the optional, you can probably rely on the compiler optimizing out the extra internal bool.

只要您不存储可选项,您就可以依靠编译器优化额外的内部布尔值。