简体   繁体   English

删除没有新建的 object (C++)

[英]Deleting an object constructed without new (C++)

I came across an article on new / operator new :我看到一篇关于new / operator new的文章:

The many faces of operator new in C++ C++新运营商的多面貌

I couldn't understand the following example:我无法理解以下示例:

int main(int argc, const char* argv[])
{
    char mem[sizeof(int)];
    int* iptr2 = new (mem) int;

    delete iptr2;       // Whoops, segmentation fault!

    return 0;
}

Here, the memory for int wasn't allocated using new , hence the segfault for delete .在这里, int的 memory 不是使用new分配的,因此是delete的段错误。

What exactly does delete not like here? delete not like 这里到底是什么? Is there some additional structure hidden when an object is initialized with new , that delete looks for?当用new初始化 object 时,是否隐藏了一些额外的结构, delete查找?

EDIT: I'll take out of comments several responses which helped me to understand the situation better:编辑:我将从评论中删除一些有助于我更好地了解情况的回复:

  1. As @463035818_is_not_a_number and @HolyBlackCat pointed out, mem was allocated on the stack, while delete tries to free memory on the heap.正如@463035818_is_not_a_number 和@HolyBlackCat 所指出的, mem是在堆栈上分配的,而delete试图在堆上释放 memory。 It's a pretty clear cut error and should lead to a segfault on most architectures.这是一个非常明显的错误,应该会导致大多数架构出现段错误。

  2. If mem was allocated on the heap without an appropriate new :如果在没有适当的new的情况下在堆上分配了mem

The only way to do it I know would be, say, to allocate an int* on a heap, then reinterpret_cast it to an array of chars and give delete a char pointer.我知道的唯一方法是,比如说,在堆上分配一个int* ,然后将它reinterpret_cast为一个字符数组,并给delete一个字符指针。 On a couple of architectures I tried this on, it actually works, but leads to a memory leak.在我尝试过的几个架构上,它确实有效,但会导致 memory 泄漏。 In general, the C++ standard makes no guarantees in this case, because doing so would make binding assumption on the underlying architecture.一般来说,C++ 标准在这种情况下不做任何保证,因为这样做会对底层架构做出绑定假设。

delete deletes objects from the heap. delete从堆中删除对象。 Your object is on the stack, not on the heap.您的 object 在堆栈上,而不是在堆上。

new ( new T , not the placement-new you used) does two things: allocates heap memory (similar to malloc() ), then performs initialization (for classes, calls a constructor). newnew T ,不是你使用的 placement-new )做了两件事:分配堆 memory (类似于malloc() ),然后执行初始化(对于类,调用构造函数)。

Placement- new (what you used) performs initialization in existing memory, it doesn't allocate its own. Placement- new (你使用的)在现有的memory 中执行初始化,它不分配自己的。

And delete does two things: calls the destructor (for class types), then frees the heap memory (similar to free() ). delete做了两件事:调用析构函数(对于 class 类型),然后释放堆 memory(类似于free() )。

Since your object is not on the heap, delete can't delete its memory.由于你的object不在堆上, delete无法删除它的memory。

There's no "placement- delete " that only calls the destructor.没有只调用析构函数的“放置- delete ”。 Instead, we have manual destructor calls:相反,我们有手动析构函数调用:

If you had a class type, you'd do iptr2->MyClass::~MyClass();如果你有一个 class 类型,你会做iptr2->MyClass::~MyClass(); to call the destructor.调用析构函数。 And freeing the memory is then unnecessary since stack memory is automatically deallocated when leaving the current scope.然后释放 memory 是不必要的,因为堆栈 memory 在离开当前 scope 时会自动释放。


Also note that you forgot alignas(int) on your char array.另请注意,您在 char 数组上忘记了alignas(int)

What exactly delete doesn't like here?究竟删除什么不喜欢这里?

The fact that it was called for a pointer that did not come from a real new .事实上,它被调用的指针并非来自真正的new

Is there some additional structure hidden when an object is initialized with new, that it looks for?当 object 用 new 初始化时,它会寻找一些额外的结构吗?

That is a near certainty for your C++ implementation , but it's completely immaterial.对于您的 C++ 实施,这几乎是肯定的,但这完全无关紧要。 This is undefined behavior, full stop.这是未定义的行为,句号。 delete is defined only for pointers to objects that were created with a non-placement new operator. delete仅针对指向使用非放置new运算符创建的对象的指针定义。 Otherwise this is undefined behavior.否则这是未定义的行为。 This is an important distinction.这是一个重要的区别。 The "your C++ implementation" part is relevant. “您的 C++ 实施”部分是相关的。 It's certainly possible that a different C++ compiler or operating system will produce code that doesn't crash, and does nothing at all.不同的 C++ 编译器或操作系统当然有可能生成不会崩溃的代码,并且什么都不做。 Or it may draw a funny face on your monitor screen.或者它可能会在您的显示器屏幕上绘制一张滑稽的脸。 Or play a tune that you hate, on your speakers.或者在扬声器上播放您讨厌的曲子。 This is what "undefined behavior" means.这就是“未定义行为”的意思。 And in this case, "undefined behavior" means a crash, in your case.在这种情况下,在您的情况下,“未定义的行为”意味着崩溃。

You can only delete what has been allocated via new .您只能delete通过new分配的内容。

As explained in the article, placement new, skips the allocation:正如文章中所解释的,placement new,跳过分配:

Calling placement new directly skips the first step of object allocation.调用placement new直接跳过第一步object分配。 We don't ask for memory from the OS.我们不要求操作系统提供 memory。 Rather, we tell it where there's memory to construct the object in [3].相反,我们告诉它哪里有 memory 来构造 [3] 中的 object。 The following code sample should clarify this:以下代码示例应阐明这一点:

You cannot delete mem because it has not been allocated via new .你不能delete mem因为它还没有通过new分配。 mem has automatic storage duration and gets freed when main returns. mem具有自动存储持续时间,并在main返回时被释放。

Placement new in your code creates an int in already allocated memory. If int had a destructor you would need to call the destructor (but not deallcoate the memory).在您的代码中放置 new 在已分配的 memory 中创建一个int 。如果int有一个析构函数,您将需要调用析构函数(但不是 deallcoate 内存)。 Placing the int in the memory of mem does not change the fact that mem is allocated on the stack.int放在mem的 memory 中并不会改变mem在堆栈上分配的事实。

Actually the placement new in the code is not that relevant for the issue in the code.实际上,代码中的新位置与代码中的问题无关。 Also this code还有这段代码

int main(int argc, const char* argv[])
{
    char mem[sizeof(int)];   
    delete iptr2;       // Whoops, Undefined    
    return 0;
}

Has undefined behavior just as your code has.与您的代码一样具有未定义的行为。

There are several flavours of new and delete . newdelete有几种风格。

The (non-placement) new operator allocates memory by calling the operator new() function. The delete operator frees memory by calling the operator delete() function. They are a pair. (非放置) new运算符通过调用operator new() function 分配 memory。 delete运算符通过调用operator delete() function 释放 memory。它们是一对。

(Confused yet? Read this , or maybe this ). (困惑了吗?阅读这个,或者也许这个)。

The new[] operator allocates memory by calling the operator new[]() function. The delete[] operator frees memory by calling the operator delete[]() function. They are a different pair. new[]运算符通过调用operator new[]() function 分配 memory。delete delete[]运算符通过调用operator delete[]() function 释放 memory。它们是不同的一对。

The placement new operator does not allocate memory and does not call any kind of operator new() -like function. There is no corresponding delete operator or operator delete() -like function. placement new operator 不分配 memory 并且不调用任何类型的operator new() -like function。没有相应的delete operator 或operator delete() -like function。

You cannot mix new of one flavour with delete of a different flavour, it makes no sense and the behaviour is undefined.您不能将一种风格的new与另一种风格的delete混合使用,这是没有意义的,并且行为是未定义的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM