在堆栈上动态分配内存
Dynamically allocating memory on stack
有这样的代码:
#include <iostream>
int main()
{
int a;
int* p = new (&a) int(2);
std::cout << a << std::endl;
// delete p; error BLOCK TYPE IS INVALID
std::cin.get();
return 0;
}
输出为:
2
为什么可以在堆栈上动态分配内存?(我认为堆是正确的地方做这个)。为什么在这种情况下,delete操作符返回错误,而new操作符可以工作?
这是使用位置新语法。放置new根本不分配内存,而是在特定位置构造对象的一种方法。在本例中,内存来自堆栈。不需要。删除出现问题,因为您没有添加内存。
有从堆栈动态分配内存的方法(alloca),但这不是这里发生的。
int* p = new (&a) int(2);
这叫做place -new。它不分配内存。它在a
相同的内存中构造对象。在placement new中,由用户指定new
操作符构造对象的内存区域。在上面的代码中,通过在new
关键字后面编写(&a)
表达式来指定内存区域。因为&a
不是动态分配的内存,所以不能delete
它:
delete p; //runtime-error
它会给出运行时错误,它试图删除变量a
所在的内存。
然而,如果你动态分配内存,那么你可以删除它。让我们假设,A
是某个类,那么你应该这样做:
char *buffer = new char[sizeof(A)]; //allocate memory of sizeof(A);
///ASSUMPTION: the buffer is properly align as required by the type A
//use placement-new to construct an object at the specified memory region
A *pA = new (buffer) A(/*..parameters..*/);
//...
//incorrect way to delete the memory!
//delete pA; //incorrect
//before deleting the memory you should be calling the destructor explicitly as
pA->~A(); //call the destructor explicitly - must do it
//now deallocate the memory as
delete []buffer;
这是placementnew最简单的例子,它只解释了语法。但故事并没有到此结束;这是一个开始,为了使它正常工作,buffer
指向的内存必须为对象类型正确对齐,在上面的例子中,我只是假设是这样。在实际代码中,您不能做出这样危险的假设。现在阅读这个FAQ:
- 什么是"新布局",为什么我要使用它?
这就是placement new
: http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.10
你可以选择传递一个地址给new,它只会调用对象的构造函数(如果有的话)。因为没有分配内存,所以用delete释放内存是错误的。只需调用对象的析构函数(如果有的话),就完成了。
c++分离了内存分配和对象生命周期的概念。与C相比,这可能是该语言最重要的"新"方面之一。在C中,没有这种区别,因为变量完全由它们的内存决定,而在c++中,对象有一个更抽象的"状态"概念,与底层内存不同。
让我们先看看内存:
{
char buf[100]; // automatic allocation, scoped lifetime
}
{
void * p = std::malloc(100); // dynamic allocation, manually managed
void * q = ::operator new(100); // essentially identical
// ...
::operator delete(q); // manual deallocation
std::free(p); // ditto
}
另一方面,对象的生命周期是一个单独的主题:
{
Foo x; // automatic storage, scoped lifetime.
// Implies automatic memory allocation for sizeof(Foo) bytes.
}
{
Foo * px = ::new Foo; // dynamic storage, manual lifetime,
// implies dynamic allocation via ::operator new()
Foo * py = ::new (q) Foo; // dynamic storage and manual lifetime, uses memory at q
// ...
delete px; // destroy object _and_ deallocate memory
py->~Foo(); // destroy object. Memory was never our business to start with.
}
正如你所看到的,内存和对象生命周期的分离增加了很多灵活性:我们可以让动态对象驻留在自动内存中,或者自己负责分配,并为重复的对象构造重用内存。标准的new
和delete
表达式结合了分配和构造,但这只是最常用操作的快捷方式。原则上,您可以完全自由地分别处理内存和对象生命周期。
这个想法支持分配器的概念,这是c++标准库中的核心概念。
- 对具有动态分配的内存和析构函数的类对象的引用
- 调用析构函数以释放动态分配的内存
- 在运行时为动态分配的内存输入值
- 释放动态分配的内存时是否需要执行此额外步骤
- 动态分配字符数组的内存
- 销毁C++中动态分配的内存(数组对象)
- 删除类成员的动态分配内存的最佳方法是什么
- 动态分配的内存构造函数
- 为什么动态分配的内存总是16字节对齐
- 如果您为类的一个对象动态分配内存作为参数,会发生什么
- 为什么动态分配的两个变量的内存位置不是连续的?
- 为浮点数组动态分配内存
- 动态分配 8 字节的内存
- 包含动态分配内存作为值的映射的取消定位速度有多快?
- STD分配器是否会在堆上动态分配内存?它可以安全地删除内存吗?
- 为什么不能在 Visual C++ 中动态分配堆栈内存?但海湾合作委员会可以做到
- 在C 中动态分配的内存的问题
- 为什么在 C++ 执行删除操作后仍可以访问释放的动态分配的内存
- 对内存动态分配的类不使用"*"的逻辑
- 如果我将内存动态分配给静态变量,我应该释放它还是会自动释放它