这个嵌套数组是使用栈内存还是堆内存?

4

假设我有一个嵌套在向量中的数组声明和使用

const int MAX_LEN = 1024;
typedef std::tr1::array<char, MAX_LEN> Sentence;
typedef std::vector<Sentence> Paragraph;

Paragraph para(256);
std::vector<Paragraph> book(2000);

我假设Sentence的内存在栈上。
对吗? 那么vectorpara的内存呢?它是在栈上,即当我的para变得太大时,我需要担心吗?
最后,书的内存怎么办?我猜肯定要在堆上,但嵌套数组在栈上,对吗?
附加问题
Paragraph的内存是否连续?
book的内存是否连续?

Fred提出了一个新问题,可能与您的连续性问题相关,还可以参考这个问题 - Kerrek SB
3个回答

6

没有堆栈。不要考虑堆栈。重要的是给定的容器类是否执行任何动态分配。

std::array<T,N>不使用任何动态分配,它只是一个自动分配的T[N]的包装器。

你放入向量中的任何东西都将由向量自己的分配器分配,这在默认情况下(通常)使用::operator new()进行动态分配。

因此,简而言之,vector<array<char,N>>vector<int>非常相似:分配器只需为其需要容纳的array<char,N>(或int)单元数分配内存,并在该内存中构造元素。嵌套向量也是如此。


对于您的“其他问题”:vector<vector<T>>对于T来说绝对不是连续的。它仅仅对于vector<T>是连续的,但那只包含内部向量的小的记账部分。内部向量的实际内容由内部向量的分配器单独分配。通常情况下,vector<S>对于类型S是连续的,没有其他内容。

我不确定vector<array<U,N>>——它可能对于U是连续的,因为数组除了包含所包含的U[N]之外没有任何数据,但我不确定是否强制执行该操作。

您可能需要将其作为单独的问题提出,这是一个好问题!


2
“没有堆栈”是不正确的说法(关于C++必须支持哪些系统的一个城市传说)。请不要传播愚蠢的城市传说。这会使初学者难以理解标准术语,例如“堆栈展开”——如果没有堆栈,那么展开就有点困难了。 - Cheers and hth. - Alf
1
用自动和动态存储期对象以及作用域来解释问题要容易得多。这也是按照标准来解释的正确方式。所以我必须同意:就像“没有勺子”一样,这只是一种简单的方式来理解某些概念,而不是变量及其寿命。(是的,我确实是指勺子,因为堆栈总是存在的,只是不相关)。 - Martin York
@Tux-D:请不要传播“技术上没有堆栈要求”的错误观念。那是不正确、虚假、愚蠢、白痴、错误等等。C++标准确保有堆栈,这不是协议问题。 - Cheers and hth. - Alf
1
@Alf:我并不是在故意挑衅,我只是不同意你的观点。而且我目前正在查阅标准,试图证明自己错了。 - Martin York
1
@Alf: 我知道我有点小气,通常来说,以栈的方式思考是完全没问题的。但对于这个问题,我真的认为这种思维方式是错误的——最初的问题“数组是否在栈上”已经走错了方向,尤其是配合“数组容器放在哪里”的问题。以自动存储和动态存储以及分配器的角度来思考会更清晰,它能让思维摆脱不必要的混乱和与概念无关的细节。 - Kerrek SB
显示剩余3条评论

2
作为一则旁注,使用 gdb 可能会有所帮助。它可以让您手动检查您的内存,包括变量的位置。您可以精确地检查自己使用的内存。

1

你的代码示例:

const int MAX_LEN = 1024;
typedef std::tr1::array<char, MAX_LEN> Sentence;
typedef std::vector<Sentence> Paragraph;

Paragraph para(256);
std::vector<Paragraph> book(2000);

我假设Sentence的内存位于堆栈上。是这样吗?不是。一个对象是否分配在堆栈上取决于声明上下文。你省略了上下文,因此无法得知。如果一个对象是局部的且非静态的,则可以为对象本身获得堆栈分配,但并不一定为其内部所引用的部分获得堆栈分配。顺便说一句,由于这里的另一个答案声称“没有堆栈”,所以请忽略关于C ++必须支持哪些系统类型的城市传说。它最初来自于对一个相当不成功的硬件级别优化计算机如何工作的误解,一些人错误地认为它没有简单的硬件支持的类似数组的堆栈实现。从" 不简单"到" 不存在"是相当牵强的,即使" 不简单"也完全错误,不仅事实上错了,而且逻辑上也是自相矛盾的。也就是说,这是一个不太聪明的初学者错误,尽管这个神话已经被至少一个有经验的人传播了。无论如何,C ++保证了一个抽象堆栈,并且在所有现有的计算机上,这个保证的抽象堆栈都是基于硬件支持的类似数组的简单堆栈实现的。

“vector para的内存怎么样?它在堆栈上吗?” 这取决于声明上下文,您没有展示。即使对象本身在堆栈上分配,它内部引用的部分(通常)也不会在堆栈上分配。

“也就是说,如果我的para变得太大,我应该担心吗?” 不需要担心。std::vector动态分配其缓冲区。它不受可用堆栈空间的限制。

“最后,book的内存怎么样?我猜它必须在堆上,但嵌套数组在堆栈上,对吗?” 不是和不是。

“段落的内存是否连续?” 不是。但是向量的缓冲区是连续的。这是因为std::array保证连续,而std::vector的缓冲区也保证连续。

“书的内存是否连续?” 不是。


@匿名的点踩者:请说明你点踩的原因,这样其他人也可以从你的见解中受益,呵呵。 - Cheers and hth. - Alf
好的,现在挑刺一下,但我认为理解C++的哲学很重要:“向量动态分配其缓冲区”当然是正确的,但并不直接与有限的堆栈空间有任何关系——真正的情况是malloc()不依赖于堆栈大小。但是我可以为我的向量编写一个分配器,它从我在声明向量之前放在堆栈上的内存缓冲区中分配。这是人为的,但它表明了语言的灵活性,以及任何给定的假设可能无法解释所有情况。 - Kerrek SB
@所有人:我不确定你们对于“段落内存的连续性”在实际中的意义是什么。这个内存并不是连续的,但缓冲区是连续的? - matias
@matias: std::vector 是一个固定大小的小对象,其中包含(可能是其他内容之一)指向缓冲区的指针,该缓冲区位于内存中的其他地方。画出来。然后考虑一下向量的向量。包含的向量对象驻留在外部向量的缓冲区中。它们中的每一个都包含指向自己缓冲区的指针。画出来。 - Cheers and hth. - Alf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接