这个内存分配在哪里分配

Where is this memory allocation allocated?

本文关键字:分配 在哪里 内存      更新时间:2023-10-16

代码行如下:

A a = static_cast<A>(*(new A)); // ?

它至少在64位clang上编译良好。

但是实际分配的内存在哪里,变量a发生了什么?

除了不需要静态强制转换之外,用new A分配的内存只是泄漏。您已经失去了对该指针的访问权限,并且再也不能正确地delete它了。

但是实际分配的内存在哪里,变量a发生了什么?

变量a一旦像往常一样离开作用域就会被销毁。

A a = static_cast<A>(*(new A)); // ?

执行以下操作。

(new A) // allocate a new A on the heap
*(new A) // the type is now A instead of *A
static_cast<A>(*(new A)) // makes it into an type A from type A in an potentially unsafe way (here it is a no-op as they are the same type)
A a = static_cast<A>(*(new A)); // copies the (default) value of A to a
; // leaks the allocted A as the last reference to it disappear.

假设这行代码出现在函数中,我将回答这个问题。如果它出现在其他地方,关于"stack"的部分是不准确的,但其他部分仍然是准确的。

这行代码编译为四个操作,我们可以将它们单独写在c++中,以使事情更清楚。它使两个分配,在两个不同的地方,其中一个被"泄露"。

A a;
{
    A *temp = new A;
    a = *temp;
}

第一个操作在"堆栈"上为A类型的对象分配空间,并默认初始化它。这个对象可以通过变量a访问。它将在函数返回时自动销毁和释放;根据周围的上下文,这可能会更早发生,但在变量a在作用域中时不会发生。

第二个操作为另一个A类型的对象分配空间,但是在"堆"而不是"堆栈"上。该对象也是默认初始化的。new操作符返回指向该对象的指针,编译器将该指针存储在一个临时变量中。(我给这个变量命名为temp,因为我必须给它一个名字;在原始代码中,无论如何都无法访问临时对象。)只有当new返回的指针在delete操作中被使用时,这个对象才会被释放。

最后,第三个操作将堆上对象的内容(由temp指向)复制到堆栈上的对象(通过变量a可访问)。(注意:您在这里写的static_cast<A>(...)没有任何影响,因为*temp已经具有A类型。因此,我把它拿出来了。

最后,存放堆上对象指针的临时变量被丢弃。当这种情况发生时,堆上的对象而不是被释放;事实上,任何东西都不可能释放它。该对象被称为有泄漏

你可能想写

A a;

在堆栈上分配对象,不做任何其他操作,或者

// note: C++11 only; C++03 equivalent is std::shared_ptr<A> a(new A());
auto a = std::make_shared<A>();

在堆上分配一个对象,并安排对它进行引用计数,以便它可能不会泄漏。(你可能还有其他一些意思,但这些是最有可能的。)

对于A的简单定义,它相当于:

A a(*new(A));

A是在堆上动态分配的,a是在堆栈上复制构造的,并且动态分配是泄露的。

对于A的一个简单定义,总体效果可能是:

new A;
A a;

这个副本实现了泄漏,而没有浪费的复制操作或混乱的,冗余的强制转换:)