删除未使用new构造的对象(C++)

iqxoj9l9  于 2023-01-22  发布在  其他
关注(0)|答案(4)|浏览(296)

我在new/operator new上看到一篇文章:
The many faces of operator new in C++
我无法理解下面的例子:

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

    delete iptr2;       // Whoops, segmentation fault!

    return 0;
}

这里,int的内存没有使用new分配,因此delete出现segfault。
delete到底不喜欢这里的什么?当用new初始化一个对象时,是否隐藏了一些delete寻找的额外结构?

**编辑:**我将从评论中删除几个帮助我更好地了解情况的回复:

1.正如@463035818_is_not_a_number和@HolyBlackCat指出的,mem是在堆栈上分配的,而delete试图释放堆上的内存,这是一个非常明显的错误,在大多数架构上应该会导致segfault。
1.如果mem在堆上分配时没有适当的new
我所知道的唯一方法是,比如说,在堆上分配一个int*,然后将其reinterpret_cast分配给一个char数组,并给予delete一个char指针。在我尝试过的几个架构上,它实际上工作正常,但会导致内存泄漏。一般来说,C++标准在这种情况下没有任何保证。因为这样做会对底层体系结构做出约束性假设。

a0x5cqrl

a0x5cqrl1#

delete从堆中删除对象。您的对象在堆栈上,而不在堆上。
newnew T,不是您使用的placement-new)执行两项操作:分配堆内存(类似于malloc()),然后执行初始化(对于类,调用构造函数)。
Placement-new(您使用的)在 existing 内存中执行初始化,它不分配自己的内存。
delete做两件事:调用析构函数(对于类类型),然后释放堆内存(类似于free())。
由于对象不在堆上,因此delete无法删除其内存。
没有只调用析构函数的“placement-delete“,而是手动调用析构函数:
如果你有一个类类型,你可以用iptr2->MyClass::~MyClass();来调用析构函数,释放内存就没有必要了,因为堆栈内存在离开当前作用域时会自动释放。
还要注意,您忘记了char数组中的alignas(int)

1aaf6o9v

1aaf6o9v2#

删除到底不喜欢这里什么?
事实上,它是为一个并非来自真实的new的指针调用的。
当一个对象用new初始化时,是否隐藏了它所寻找的其他结构?
对于你的C实现来说,这几乎是肯定的,但这是完全不重要的。句号。delete仅为指向使用非位置new运算符创建的对象的指针定义。否则,这是未定义的行为。这是一个重要的区别。“您的C实现”部分是相关的。当然,不同的C++一个编译器或操作系统将产生不会崩溃的代码,而且什么都不做。或者它可能会在你的监视器屏幕上画一张滑稽的脸。或者在你的扬声器上播放你讨厌的曲调。这就是“未定义的行为”的意思。在这种情况下,“未定义的行为”在你的情况下意味着崩溃。

nbewdwxp

nbewdwxp3#

您只能delete已通过new分配的内容。
正如本文中所解释的,placement new跳过了分配:
直接调用placement new跳过了对象分配的第一步。我们不向操作系统请求内存。相反,我们告诉它哪里有内存来构造[3]中的对象。下面的代码示例应该澄清这一点:
不能使用deletemem,因为它尚未通过new分配。mem具有自动存储持续时间,并在main返回时释放。
在代码中放置new会在已分配的内存中创建一个int。如果int有析构函数,则需要调用析构函数(但不释放内存)。将int放置在mem的内存中不会改变mem在堆栈上分配的事实。
实际上,代码中的新位置与代码中的问题并不相关。

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

具有未定义的行为,就像您的代码具有的那样。

dxxyhpgq

dxxyhpgq4#

有几种口味的newdelete
(非布局)new操作符通过调用operator new()函数来分配内存。delete操作符通过调用operator delete()函数来释放内存。它们是一对。
(还不明白吗?读this,或者这个)。
new[]操作符通过调用operator new[]()函数来分配内存。delete[]操作符通过调用operator delete[]()函数来释放内存。它们是不同的一对。
放置new运算符不分配内存,也不调用任何类似operator new()的函数。没有对应的delete运算符或类似operator delete()的函数。
你不能把一种口味的new和另一种口味的delete混合在一起,这是没有意义的,行为也是不确定的。

相关问题