我有一个理论上的问题而不是实际问题,因为我只想知道在某种情况下会发生什么,而不是任何实际情况。因此,例如,如果我创建一个智能指针对象var componentA = require('./componentA');
var componentB = require('./componentB');
var navigationComponents = [componentA, componentB];
render() {
return(
<div>
_.map(navigationComponents, Component) {
return <Component />;
}
</div>
)
}
,然后在该对象内创建像std::uniqe_ptr<City> smallville(new City);
这样的对象,那么这些对象是否仍会在堆上创建,即使语法是用于在堆栈上创建它们?或者使用智能指针创建更多对象是否更好?
答案 0 :(得分:4)
让我们看一下简单的案例:
class B{
long b;
};
class A{
B b;
int a;
};
如果你在堆栈上声明,就像这样:
A a;
该对象将在具有连续字节的堆栈上完全声明。
如果我们在堆上声明,就像这样:
A* a = new A();
该对象将在具有连续字节的堆上完全声明。
使用智能指针的事实不会改变这种行为,所有内容都将在堆上声明。智能指针只用解除分配机制包装原始指针。
如果我们向前迈出这一步,我会说智能指针不会改变分配机制。让我们看看下面的例子:
class C{
int* c;
public:
C(void* buffer) : c(new (buffer) int(5)){}
};
int main (){
char stackBuffer[100];
unique_ptr<C> c = std::make_unique<C>(stackBuffer);
}
这里,C的构造函数获取一些缓冲区来分配一个整数。 std :: unique_ptr没有改变分配机制,整数仍然是从堆栈分配的缓冲区中分配的,尽管C是从堆中分配的。
甚至更简单:
class E{};
int main (void){
char buffer [100];
unique_ptr<E> c(new(buffer) E());
};
unique_ptr
仅包装new
运算符返回的指针。 new
从堆栈的缓冲区中分配了对象。
您可能会对所有这些示例感到困惑,但答案仍然很简单 - 智能指针保留您提供的分配机制。在没有任何placement new
的情况下,无论对象是否包含内部对象,都将从堆中分配出来。所有这些都将在堆上声明。如果你提供不同的分配机制 - 智能指针将保留它。再一次,它的整个任务是用相关的析构函数包装原始指针,该析构函数将取消分配内存。
答案 1 :(得分:1)
如果b1
和b2
是City
类的非静态成员,那么它们将被放置在为City
分配的内存块中 - 将会有没有任何单独的分配。
如果b1
和b2
是其中一个City
方法中的本地人,则该情况与任何函数没有区别,它们将被置于堆栈中。< / p>
当然,如果Building
在其ctor中通过new
进行任何分配,那么分配的对象就是堆上的单独块。
答案 2 :(得分:0)
使用您所谓的“on the stack”语法声明的对象(自动生存期,而不是堆分配对象的动态生存期)实际上是它们的封闭对象或范围,它们的生命周期是紧密相连的。
因此,如果在堆栈中分配一个对象(函数体中为Foo foo;
),则该对象及其所有自动子对象将存在于堆栈中。
在全局范围内声明的对象就像最大生命周期的自动对象(与程序本身相同),但物理存储在静态内存中。
如果在堆上分配一个对象,它的所有自动子对象也将与它一起存在于堆中。
注意:这不是C ++标准的一部分(只有生命周期和范围在那里定义),但实际上在“通常”实现中会发生这种情况。
答案 3 :(得分:0)
smallville正在堆叠,但是Smallville指向的新对象是Heap。
答案 4 :(得分:0)
“在堆栈上创建它们(建筑物)的语法是什么?” Building b1
背景不足。这将在周围的上下文中创建对象。如果周围的上下文是一个函数,那么构建将具有函数作用域(“在堆栈上”)。如果周围的上下文是一个类,那么对象将是类成员。如果没有周围的上下文(除了程序本身),该对象将是一个全局的,并且在该程序的生命周期中存在。