如何安全地从内存中清除使用 new 关键字创建的对象(带有属性)?
Posted
技术标签:
【中文标题】如何安全地从内存中清除使用 new 关键字创建的对象(带有属性)?【英文标题】:How do you safely clear an object from memory (with attributes) which was created using the new keyword? 【发布时间】:2021-09-04 13:00:18 【问题描述】:据我所知,每个“新”调用都需要对该对象进行相应的“删除”调用。那么这真的正确吗?:
using namespace std;
class Box
public:
double length;
char letters_in_box[80];
;
int main()
Box *b = new Box;
b->length = 2.0;
b->letters_in_box = "Hello world";
//Some code with b
delete b;
return 0;
与“length” double 和“letters_in_box”数组关联的内存是否被此清除?
【问题讨论】:
我猜你的意思是“来自另一个进程”,然后答案是操作系统特定的。请在您的问题中提供一些minimal reproducible example,并注意C++ rule of five。你可能想定义一个 C++ 析构函数 无法保证,我认为你不应该问自己这个问题。 我认为b->letters_in_box = "Hello world";
不会编译,因为letters_in_box
是一个数组。
假设所有这些都发生在同一个函数或块中,那么您可能根本不想使用动态存储持续时间。而是使用auto b = Box();
。
你也应该使用std::string
。鉴于您的简单代码存在很多问题,我强烈建议您阅读一些有关 C++ 的书籍。 C++ 不是即兴创作的好语言,因为有很多可能的陷阱。
【参考方案1】:
是的。当您删除 b
时,它也会删除 letters_in_box
数组。
但是,对于你的b->letters_in_box = "Hello world";
,你会得到一个编译错误:“error C3863: array type 'char [80]' is not assignable”
#include <memory> // For 'memcpy_s' (since C11)
class Box
public:
double length;
char letters_in_box[80];
;
int main()
Box* b = new Box;
b->length = 2.0;
// b->letters_in_box = "Hello world"; ** Compile Error C3863: array type 'char [80]' is not assignable **
memcpy_s(b->letters_in_box, sizeof(b->letters_in_box), "Hello world", sizeof("Hello world"));
// Some code with b
delete b;
现代 C++
比new
更好的做法是智能指针,例如,在出现异常的情况下您根本不必担心删除:
#include <memory> // For 'std::unique_ptr' and for 'memcpy_s'
class Box
public:
double length;
char letters_in_box[80];
;
constexpr char my_text[] = "Hello world";
int main()
auto b = std::make_unique<Box>(); // No need to delete
b->length = 2.0;
memcpy_s(b->letters_in_box, sizeof(b->letters_in_box), my_text, sizeof(my_text));
// Some code with b
另外,(而不是 C 数组)我更喜欢使用 C++ 数组:
#include <array> // For 'std::array'
#include <memory> // For 'std::unique_ptr' and for 'memcpy_s'
class Box
public:
double length;
std::array<char, 80> letters_in_box;
;
constexpr char my_text[] = "Hello world";
int main()
auto b = std::make_unique<Box>(); // No need to delete
b->length = 2.0;
memcpy_s(&b->letters_in_box, b->letters_in_box.size(), my_text, sizeof(my_text));
//Some code with b
--
最后一条评论:如果不限制使用char[]
,我会改用std::string
:
#include <string> // For 'std::string'
#include <memory> // For 'std::unique_ptr'
class Box
public:
double length;
std::string letters_in_box;
;
int main()
auto b = std::make_unique<Box>(); // No need to delete
b->length = 2.0;
b->letters_in_box = "Hello world";
//Some code with b
【讨论】:
memcpy
具有未定义的行为,因为它访问的 char 远远超过了 C 字符串文字的结尾。
@Eljay 感谢您的评论。我切换到 memcpy_s。【参考方案2】:
在现代 C++ 中,强烈建议不要使用 new 和 delete,因为 Karen 在上面提到过,如果在程序期间由于任何原因发生异常,并且您的异常处理会导致不返回运行删除的分支,则会导致内存泄漏。
相反,我会考虑使用智能指针 (https://en.cppreference.com/book/intro/smart_pointers) 来创建指向所用对象的新指针,因为一旦它们超出范围(唯一指针)(即异常分支),它们将允许释放内存然后不返回相同的范围),或者一旦它们的“引用”数量到期(共享指针)。
关于您编写的显式代码,是的,一旦该类被删除,“length”双精度和“letters_in_box”数组将被删除,但重要的是要注意,如果您显式使用了 malloc/calloc/etc为了分配内存,则应使用类析构函数来释放此内存。
编辑:也强烈建议阅读 RAII (https://en.cppreference.com/w/cpp/language/raii),因为它确实是现代、安全 C++ 的基础。
【讨论】:
【参考方案3】:那么这真的正确吗?
是的,没错。但是,在删除b
之前,你必须确保它没有抛出异常。
例如:
Box *b = new Box;
b->length = 2.0;
b->letters_in_box = "Hello world";
throw 5; //this is not usually done.
delete b;
在此示例中,如果在调用delete
之前未处理异常,则会出现memory leak。
【讨论】:
那么如何保证即使出现异常也被删除呢? @CoderAlpha,你必须在调用delete
之前处理异常。
@CoderAlpha 最好的办法是完全避免使用new
和delete
。在现代 c++ 中,您很少需要 new
和 delete
。如果您创建的对象应该只存在于函数或块中,只需编写Box b = Box();
。如果您需要转让所有权,您可以使用unique_ptr
,如果unique_ptr
不符合您的需求,您可以使用shared_ptr
。
所以Box b = Box();
不需要任何删除,因为它在堆栈上,对吧?但是如果我们需要比堆栈大小更多的内存怎么办?
@CoderAlpha 是的。如果Box
包含的数据量可能超过堆栈,您可以使用unique_ptr
(std::unique_ptr<Box> b = std::make_unique<Box>();
)。或者将Box
的一个(或多个)成员更改为不同的名称,例如std::vector
。但是选择什么解决方案取决于实际用例。以上是关于如何安全地从内存中清除使用 new 关键字创建的对象(带有属性)?的主要内容,如果未能解决你的问题,请参考以下文章