这是正确的释放新对象的方式吗?

huangapple go评论64阅读模式
英文:

Is this the correct way to deallocate a new object?

问题

以下是代码的翻译部分:

#include <iostream>

class Dude
{
public:
    int age;

    Dude(int age)
    {
        this->age = age;
    }
};

int main(int argc, char* argv[])
{
    Dude *dude1 = new Dude(21);
    std::cout << dude1->age << '\n';

    delete dude1;

    return 0;
}

这段代码的主要目的是创建一个名为"Dude"的类,然后在main函数中创建一个"Dude"类的实例,使用new运算符分配内存,并在程序结束时使用delete运算符释放内存。以下是关于你提到的其他问题的回答:

  • 是的,使用delete dude1; 是正确的方法来释放 dude1 的内存并销毁 dude1 对象。

  • 如果保留默认析构函数,它将不执行任何额外的内存清理或资源释放,因为在默认析构函数中没有显式的清理代码。默认析构函数的存在是为了确保对象被销毁时,与其相关的内存被释放,但在这个特定的情况下,Dude 类没有需要额外处理的资源。

  • dude1->~Dude(); 这行代码调用了 Dude 类的析构函数,手动销毁了 dude1 对象。通常情况下,不需要手动调用析构函数,因为在对象离开其作用域或通过 delete 运算符释放内存时,析构函数会自动被调用。手动调用析构函数通常不是必要的,只有在特殊情况下才会使用。

英文:
#include &lt;iostream&gt;

class Dude
{
public:
	int age;

	Dude(int age)
	{
		this-&gt;age = age;
	}
};

int main(int argc, char* argv[])
{
	Dude *dude1 = new Dude(21);
	std::cout &lt;&lt; dude1-&gt;age &lt;&lt; &#39;\n&#39;;

	delete dude1;

	return 0;
}

Is this the correct way to deallocate the memory of dude1 and to destroy the object dude1?

What memory deallocation and cleanup is the destructor doing if left as the default destructor?

dude1-&gt;~Dude();

What does this piece of code do?

答案1

得分: 5

This is the translated text:

> Is this the correct way to deallocate the memory of dude1 and to destroy the object dude1?

这是否是释放dude1的内存并销毁对象dude1的正确方式?

Yes, it is technically correct.

是的,从技术上讲是正确的。

But, it is not the best option. A better option would be to create the Dude object in automatic storage, and not worry about its deallocation/cleanup at all, let the compiler worry about that for you, eg:

但这不是最佳选项。更好的选择是在自动存储中创建Dude对象,完全不用担心它的释放/清理工作,让编译器来处理,例如:

int main(int argc, char* argv[])
{
    Dude dude1(21);
    std::cout &lt;&lt; dude1.age &lt;&lt; '\n';

    return 0;
}

如果必须动态创建对象,至少要使用std::unique_ptr之类的智能指针,这样就不需要手动delete对象,例如:

#include <memory>

int main(int argc, char* argv[])
{
    auto dude1 = std::make_unique<Dude>(21);
    // 在C++14之前,可以使用以下方式代替:
    // std::unique_ptr<Dude> dude1(new Dude(21));

    std::cout &lt;&lt; dude1->age &lt;&lt; '\n';

    return 0;
}

> What memory deallocation and cleanup is the destructor doing if left as the default destructor?

如果将析构函数保留为默认析构函数,它会执行什么内存释放和清理操作?

In this example, nothing at all.

在这个例子中,根本什么都不做。

In general, when you deal with objects, there is a clear separation of responsibilities between allocation/deallocation and creation/destruction. Memory for the object is reserved first, then the object is created within that memory. Later, the object is destroyed first, and then its memory is released.

一般而言,当你处理对象时,分配/释放创建/销毁 之间有明确的责任分工。首先保留对象的内存,然后在该内存中创建对象。随后,首先销毁对象,然后释放其内存。

When an object has automatic storage duration, its memory is reserved within the calling scope (ie, a local variable in a function/block, a data member of a class, etc), and it is created within that scope's memory. When that scope ends (ie, the function/block ends, the containing object is destroyed, etc), the scoped object is automatically destroyed and its memory is released.

当一个对象具有自动存储期时,其内存在调用作用域内被保留(例如,在函数/块中的局部变量、类的数据成员等),并在该作用域的内存中创建。当该作用域结束时(即函数/块结束、包含的对象被销毁等),作用域内的对象将被自动销毁,其内存将被释放。

Thus, in your example, the default destructor of Dude does nothing, since there is nothing for it to destroy.

因此,在您的示例中,Dude的默认析构函数不执行任何操作,因为没有需要销毁的内容。

Dude has a single int data member, which is created with automatic storage duration within Dude. When a Dude object is created, space for the int is included in the memory allocation for the Dude object, but the int is not valid for use until the Dude object is constructed within that memory. Later, when the Dude object is destroyed, the int becomes invalid for use when the Dude object's destructor is called, and then the memory for the int disappears when the memory for the Dude object is deallocated.

Dude有一个int数据成员,它在Dude内具有自动存储期。当创建一个Dude对象时,为Dude对象的内存分配中包括了int的空间,但在Dude对象在该内存中构造之前,int不可用。随后,当销毁Dude对象时,Dude对象的析构函数被调用时,int变得不可用,并且当Dude对象的内存被释放时,int的内存也会消失。

In my first example above, the Dude object has automatic storage duration. Its scope is main(), so the compiler reserves memory inside the stack frame of main() to hold the Dude object, and then creates the Dude object (ie, calls its constructor) within that memory. When main() exits, the Dude object goes out of scope and is destroyed (ie, its destructor is called), and its memory is released when the stack frame is cleaned up.

在我上面的第一个示例中,Dude对象具有自动存储期。其作用域是main(),因此编译器在main()的堆栈帧内部保留内存以容纳Dude对象,然后在该内存中创建Dude对象(即调用其构造函数)。当main()退出时,Dude对象超出作用域并被销毁(即调用其析构函数),当堆栈帧被清理时,它的内存被释放。

In my second example above, the Dude object has dynamic storage duration. Its scope is dynamic memory. new allocates dynamic memory to hold the Dude object, and then creates the Dude object (ie, calls its constructor) within that memory. Later, delete destroys the Dude object (ie, calls its destructor) and deallocates the dynamic memory that new had allocated.

在我上面的第二个示例中,Dude对象具有动态存储期。其作用域是动态内存

英文:

> Is this the correct way to deallocate the memory of dude1 and to destroy the object dude1?

Yes, it is technically correct.

But, it is not the best option. A better option would be to create the Dude object in automatic storage, and not worry about its deallocation/cleanup at all, let the compiler worry about that for you, eg:

int main(int argc, char* argv[])
{
    Dude dude1(21);
    std::cout &lt;&lt; dude1.age &lt;&lt; &#39;\n&#39;;

    return 0;
}

If you must create the object dynamically, at least use a smart pointer like std::unique_ptr so you don't need to delete the object manually, eg:

#include &lt;memory&gt;

int main(int argc, char* argv[])
{
    auto dude1 = std::make_unique&lt;Dude&gt;(21);
    // prior to C++14, use this instead: 
    // std::unique_ptr&lt;Dude&gt; dude1(new Dude(21));

    std::cout &lt;&lt; dude1-&gt;age &lt;&lt; &#39;\n&#39;;

    return 0;
}

> What memory deallocation and cleanup is the destructor doing if left as the default destructor?

In this example, nothing at all.

In general, when you deal with objects, there is a clear separation of responsibilities between allocation/deallocation and creation/destruction. Memory for the object is reserved first, then the object is created within that memory. Later, the object is destroyed first, and then its memory is released.

When an object has automatic storage duration, its memory is reserved within the calling scope (ie, a local variable in a function/block, a data member of a class, etc), and it is created within that scope's memory. When that scope ends (ie, the function/block ends, the containing object is destroyed, etc), the scoped object is automatically destroyed and its memory is released.

Thus, in your example, the default destructor of Dude does nothing, since there is nothing for it to destroy.

Dude has a single int data member, which is created with automatic storage duration within Dude. When a Dude object is created, space for the int is included in the memory allocation for the Dude object, but the int is not valid for use until the Dude object is constructed within that memory. Later, when the Dude object is destroyed, the int becomes invalid for use when the Dude object's destructor is called, and then the memory for the int disappears when the memory for the Dude object is deallocated.

In my first example above, the Dude object has automatic storage duration. Its scope is main(), so the compiler reserves memory inside the stack frame of main() to hold the Dude object, and then creates the Dude object (ie, calls its constructor) within that memory. When main() exits, the Dude object goes out of scope and is destroyed (ie, its destructor is called), and its memory is released when the stack frame is cleaned up.

In my second example above, the Dude object has dynamic storage duration. Its scope is dynamic memory. new allocates dynamic memory to hold the Dude object, and then creates the Dude object (ie, calls its constructor) within that memory. Later, delete destroys the Dude object (ie, calls its destructor) and deallocates the dynamic memory that new had allocated.

Note that the int inside of Dude always has automatic storage duration. Its scope is Dude, so it gets allocated wherever a Dude object is allocated, and is deallocated whenever the Dude object is deallocated. Whether that be in automatic memory (ie, the stack) or in dynamic memory (ie, the heap).

> dude1-&gt;~Dude();
>
> What does this piece of code do?

It explicitly calls the object's destructor, like any other method call. However, DO NOT DO THIS, except for objects that have been constructed with placement-new, eg:

int main(int argc, char* argv[])
{
    // FYI, this is not the correct way to ensure the allocated memory
    // is satisfactory for creating an object in it, this is simplified
    // just for demonstration purposes!
    char *buffer = new char[sizeof(Dude)];

    Dude *dude1 = new (buffer) Dude(21);
    std::cout &lt;&lt; dude1-&gt;age &lt;&lt; &#39;\n&#39;;

    dude1-&gt;~Dude();

    delete[] buffer;

    return 0;
}

huangapple
  • 本文由 发表于 2023年3月4日 09:37:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/75633153.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定