热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

数组作为模板参数:堆栈还是堆?-Arrayastemplateparameter:stackorheap?

Myknowledgeofthestackascomparedwiththeheapisveryrudimentary,butwhenitcomestoarrays

My knowledge of the stack as compared with the heap is very rudimentary, but when it comes to arrays, from what I know something like this is created on the stack

与堆相比,我对堆栈的了解非常简陋,但是当涉及到数组时,从我所知道的内容就是在堆栈上创建的

float x[100];

whereas something like this is created on the heap

而这样的东西是在堆上创建的

float* x = new float[100];

But what happens if I create a template array class, and pass it in a "stack" array type (like float[100])? Example:

但是如果我创建一个模板数组类并将其传递给“堆栈”数组类型(如float [100])会发生什么?例:

#include 

using namespace std;

template 
class Array {
public:
    int size;
    T* data;

    Array(int size_) : size(size_) {
        data = new T[size];
    }

    ~Array() {
        delete [] data;
    }
};

int main() {
    int m = 1000000;
    const int n = 100;
    Array* array = new Array(m);

    for (int i = 0; i data[i][j] = i * j;

    cout <data[10][9] <

What exactly is going on here? Is this memory created on the stack, or on the heap? My guess is the heap, but how does this work? Does the compiler allocate one large block of memory, and then store pointers that index into it every n elements? Or does it allocate many smaller blocks of memory (not necessarily contiguous), and store pointers to each block?

到底发生了什么?这个内存是在堆栈上还是在堆上创建的?我的猜测是堆,但这是如何工作的?编译器是否分配一个大的内存块,然后存储每n个元素索引到它的指针?或者它是否分配了许多较小的内存块(不一定是连续的),并存储指向每个块的指针?

Furthermore, I can't seem to do this without the aid of a template. Specifically, this code does not compile:

此外,没有模板的帮助,我似乎无法做到这一点。具体来说,此代码无法编译:

int m = 1000;
const int n = 100;
(float[n])* array = new (float[n])[m];

What is going on here?

这里发生了什么?

EDIT:

Thanks for the syntax tips, everyone. What I was really interested in is what happens in the block

感谢大家的语法提示。我真正感兴趣的是块中发生的事情

int m = 1000;
const int n = 100;
float (*array)[n] = new float[m][n];

but I didn't know how to write it without the use of templates. One thing I was really interested in is if the compiler allocates this as one large block on the heap, how can you use the syntax array[i][j] to access a particular element without storing pointers to every n-th element? Then I realized that since n is constant, sizeof(float[n]) is fixed, so when you make the array, the compiler is allocating an array of m elements where each element is a float[n], which in my case is 100 * 4 = 400 bytes. Now it all makes sense. Thanks!

但我不知道如何在不使用模板的情况下编写它。我真正感兴趣的一件事是,如果编译器将其分配为堆上的一个大块,那么如何使用语法数组[i] [j]访问特定元素而不存储指向每个第n个元素的指针?然后我意识到由于n是常量,sizeof(float [n])是固定的,所以当你创建数组时,编译器会分配一个m元素的数组,其中每个元素都是一个float [n],在我的例子中是100 * 4 = 400字节。现在一切都有道理。谢谢!

4 个解决方案

#1


2  

You've written your array extents backwards. This works:

你已经向后编写了数组范围。这有效:

  int m = 1000;
  const int n = 100;
  float (*array)[n] = new float[m][n];
  delete[] array;

If you want to keep the array extents in the same order you can use a type alias or appropriate template:

如果要以相同的顺序保留数组范围,可以使用类型别名或适当的模板:

  using A = float[n];
  A* array = new A[m];

or

// at file scope
template using add_extent = T[N];
// ...
  add_extent* array = new add_extent[m];

A multidimensional array whether on the stack or the heap is allocated as a single block of m*n elements. When you index a pointer to array type (like float (*array)[n]), the pointer is incremented n elements at a time, per the stride of the array type.

无论是在堆栈还是堆上的多维数组都被分配为m * n个元素的单个块。当您将指针索引到数组类型(如float(* array)[n])时,指针会按照数组类型的步幅一次递增n个元素。

#2


3  

Array* array = new Array(m);

What is going on here is two heap allocations. The Array object will be allocated on the heap because you used new to create it. The new-expression calls the Array constructor, which again uses new to allocate the array data; therefore data is also allocated on the heap.

这里发生的是两个堆分配。 Array对象将在堆上分配,因为您使用new来创建它。 new-expression调用Array构造函数,它再次使用new来分配数组数据;因此,数据也在堆上分配。

It is better to do this:

最好这样做:

Array array(m);

This allocates array on the stack (so it will automatically be destroyed at the end of the block). However, while the array object itself is on the stack, the data is still stored on the heap because it's allocated on the heap in the Array constructor. This is similar to what happens when you have a std::vector or std::string local variable.

这会在堆栈上分配数组(因此它会在块的末尾自动销毁)。但是,虽然数组对象本身位于堆栈上,但数据仍然存储在堆上,因为它是在Array构造函数的堆上分配的。这类似于当你有一个std :: vector或std :: string局部变量时会发生的事情。

Furthermore, I can't seem to do this without the aid of a template. Specifically, this code does not compile:

此外,没有模板的帮助,我似乎无法做到这一点。具体来说,此代码无法编译:

This is just because your syntax is wrong. The correct syntax is:

这只是因为你的语法错误。正确的语法是:

float (*array)[n] = new float[m][n];

The left-hand side shows the correct way to declare a pointer to an array. For the right-hand side, you want an array of m float[n]s. This is denoted float[m][n]; the [m] doesn't go at the end.

左侧显示了声明指向数组的指针的正确方法。对于右侧,您需要一个m float [n]的数组。这表示为float [m] [n]; [m]最后没有结束。

#3


1  

All the memory goes on the heap. The compiler allocates one giant chunk of memory for the array-of-arrays, and sets up the indexing so that it's accessible.

所有内存都在堆上。编译器为数组数组分配一个巨大的内存块,并设置索引以便可访问。

And as an aside if anyone ever copies or assigns your Array class you'll leak memory and/or double delete.

另外,如果有人复制或分配你的Array类,你将泄漏内存和/或双重删除。

#4


0  

In the line

在线

Array* array = new Array(m);

An instance of Array is allocated on the heap. You already understood that, given your first statement about allocations in general.

在堆上分配Array 的实例。你已经明白了,一般来说你的第一个关于分配的陈述。

Perhaps the confusing part is the use of float[n] as a template parameter?

也许令人困惑的部分是使用float [n]作为模板参数?

The template parameter T, as denoted by the keyword class in your definition of Array, represents a type. It isn't in itself related to any form of allocation.

模板参数T(由Array定义中的关键字class表示)表示一种类型。它本身与任何形式的分配无关。

As a demonstration of this, let's write a simple template which doesn't make any use of its parameter:

作为对此的演示,让我们编写一个简单的模板,它不会使用它的参数:

#include 

using namespace std;

template 
class A {
};

int main(){

    A a1;
    A a2;
    float f[100];

    assert(sizeof(a1) == sizeof(a2));
    cout <<"a1 : " <

Output:

a1 : 1
f : 400

So float[n] here is indeed a type(1).

所以float [n]在这里确实是一个类型(1)。

On the other end, when you use the keyword new, you know that something is being allocated on the heap. So as I said, the array variable will point to a memory chunk in the heap. Furthermore the template itself contains a heap allocation (again, keyword new).

另一方面,当您使用关键字new时,您知道正在堆上分配某些内容。正如我所说,数组变量将指向堆中的内存块。此外,模板本身包含堆分配(同样,关键字new)。

Finally, I would like to nuance the basic premise that new indicates a heap allocation. While by default it is the case, when used in placement mode, the actual allocation could very well be on the stack.

最后,我想细化新的表明堆分配的基本前提。虽然默认情况下是这样,但在放置模式下使用时,实际的分配很可能在堆栈上。


(1) Note that C++ accepts it as such because n is declared as a constant, and thus the resulting type may be evaluated at compilation time. Remove the const trait of the definition of n, and the compiler will complain.

(1)注意C ++接受它是因为n被声明为常量,因此可以在编译时评估结果类型。删除n定义的const特性,编译器会抱怨。


推荐阅读
  • 使用C++编写程序实现增加或删除桌面的右键列表项
    本文介绍了使用C++编写程序实现增加或删除桌面的右键列表项的方法。首先通过操作注册表来实现增加或删除右键列表项的目的,然后使用管理注册表的函数来编写程序。文章详细介绍了使用的五种函数:RegCreateKey、RegSetValueEx、RegOpenKeyEx、RegDeleteKey和RegCloseKey,并给出了增加一项的函数写法。通过本文的方法,可以方便地自定义桌面的右键列表项。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • Igotthiscode(IknowitsinSpanishIcantranslateifneeded)wheretheygivemethefunctionS ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • 本文讨论了一个数列求和问题,该数列按照一定规律生成。通过观察数列的规律,我们可以得出求解该问题的算法。具体算法为计算前n项i*f[i]的和,其中f[i]表示数列中有i个数字。根据参考的思路,我们可以将算法的时间复杂度控制在O(n),即计算到5e5即可满足1e9的要求。 ... [详细]
  • AtonepointIhadlookedatimplementingaclasstemplateinC++thatwouldsupportanEnumthatwo ... [详细]
  • STL学习笔记--数值算法
    数值算法  C++STL的数值算法(Numericalgorithms)是一组对容器元素进行数值计算的模板函数,包括容器元素求和accumulate、两序列元素的内积inner_pro ... [详细]
  • [置顶]        C++类的构造函数与析构函数的调用顺序
    1构造函数的调用顺序[1]构造函数按此顺序执行工作:按声明顺序调用基类和成员构造函数。如果类派生自虚拟基类,则会将对象的虚拟基指针初始化。如果类具有或继承了虚函数,则会将对象的虚函数指针初始化。 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • 本文介绍了一种划分和计数油田地块的方法。根据给定的条件,通过遍历和DFS算法,将符合条件的地块标记为不符合条件的地块,并进行计数。同时,还介绍了如何判断点是否在给定范围内的方法。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • 预备知识可参考我整理的博客Windows编程之线程:https:www.cnblogs.comZhuSenlinp16662075.htmlWindows编程之线程同步:https ... [详细]
author-avatar
DYongLi
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有