【问题标题】:Template non-type parameters and allocating array memory模板非类型参数和分配数组内存
【发布时间】:2014-08-19 18:55:10
【问题描述】:

我正在阅读的书中有一个示例类用于解释概念:

class Gameboard{
public:
    Gameboard(int inWidth, int inHeight);
    Gameboard(const Spreadsheet& src);
    Gameboard& operator=(const Spreadsheet& rhs);

private:
    GamePiece** mCells;
    size_t width;
    size_t height;
};

然后他们引入模板并引入更新的类:

template<typename T>
class Grid{
public:
    Grid<T>(int inWidth, int inHeight);
    Grid<T>(const T& src);
    Grid<T>& operator=(const T& rhs);

private:
    T** mCells;
    size_t width;
    size_t height;
};

最后他们引入了非类型模板参数并说你现在可以这样做了:

template<typename T, size_t WIDTH, size_t HEIGHT>
class Grid{
public:
    Grid<T>();
    Grid<T>(const T& src);
    Grid<T>& operator=(const T& rhs);

private:
    T mCells[WIDTH][HEIGHT];
};

从书中:

在 Grid 模板类中,您可以使用非类型模板参数来指定网格的高度和宽度,而不是在构造函数中指定它们。在模板列表而不是构造函数中指定非类型参数的主要优点是在编译代码之前这些值是已知的。回想一下,编译器通过在编译之前替换模板参数来为模板化方法生成代码。 因此您可以在实现中使用普通的二维数组,而不是动态分配它

我对这种动态内存分配方法并不感到兴奋。首先,这是否意味着多维数组将在堆栈上(因为他们似乎暗示它不会被动态分配)?我不明白你为什么不想在堆上动态分配内存?

其次,是否有一些 C++ 规则(我忘记了)禁止在堆栈上声明多维数组,因此这种方法令人兴奋?

我试图了解在他们的示例中使用非类型模板参数有什么好处。

【问题讨论】:

  • 将其视为说明性的,继续学习,查看其他信息来源。我不能仅仅通过这个样本来判断这本书,所以对我来说这不是很有说服力,有很多设计决策可以给你使用这种类型的环境,例如std::array,提供相同的路线std::vector 的替代品。

标签: c++ templates multidimensional-array non-type


【解决方案1】:

首先这是否意味着多维数组将在堆栈上(因为他们似乎暗示它不会被动态分配)?

如您所见,您的数组直接是一个成员,它没有被指针间接引用。

T mCells[WIDTH][HEIGHT];

但是说它在堆栈或堆上是不正确的,因为实际上数组是对象的一部分,它的位置取决于对象的分配位置和方式。如果对象是在堆上分配的,它的数组子对象也是,如果整个对象在栈上,数组也是。

我不明白你为什么不想在堆上动态分配内存?

你可以。但是拥有一个新的数组既慢又容易出错(即它应该被删除等)。

其次,是否有一些 C++ 规则(我忘记了)禁止在堆栈上声明多维数组,因此这种方法令人兴奋?

没有。但是任何数组的大小都必须是编译时常量。非类型模板参数正是 - 编译时常量。如果它们只是 int 类型的函数参数,编译器将不知道它们的值,并且在堆栈上创建数组(多维或其他)是非法的。

【讨论】:

  • '但是任何数组的大小都必须是编译时常量' 至少 GCC 有扩展(对于本地堆栈分配的数组),应该可以克服这个问题吗?跨度>
【解决方案2】:

“首先这是否意味着多维数组将在堆栈上”

如果Gameboard 位于堆栈上(即它是一个局部变量),那么是的,数组也在堆栈上。

“我不明白你为什么不想在堆上动态分配内存?”

为了速度。在这种情况下,由于Gameboard 可能会持续很长时间,因此没有必要。其实std::vector&lt;std::vector&lt;GamePiece&gt;&gt; mCells会比手动数组好。

“是否有一些 C++ 规则(我忘记了)禁止在堆栈上声明多维数组”

不,这是允许的。但与普通数组一样,维度必须在编译时就知道。

“我试图了解在他们的示例中使用非类型模板参数有什么好处。”

这是一个人为的例子。

假设您要创建一个任意精度的整数类。精度越高,需要的空间就越大。这个类可能会被频繁地创建和销毁,就像一个普通的整数变量一样。如果数据是动态分配的,则速度较慢。通过使用模板参数指定所需的精度,可以创建所需大小的常规数组作为类的成员。每当类入栈时,数组也会入栈,这样会更快。

【讨论】:

    【解决方案3】:

    在不提及您提供的特定示例和来源的情况下:

    我对这种动态内存分配方法并不感兴趣

    因为根本不需要动态分配,即使您在堆栈上创建实例也是如此。

    我不明白你为什么不想在堆上动态分配内存?

    我经常在小型嵌入式系统上工作,有时我什至无法进行动态内存管理(或者我不想承担开销)。对于这样的系统,并且您事先非常清楚,您可以/想要实际拥有哪些大小,这是一个非常好的配置抽象,您希望将其用于目标特定平台实现。

    除了上述原因之外,动态分配会在运行时引入性能影响,这对于性能关键型应用程序(例如游戏框架渲染引擎)来说是不希望的。

    简而言之:
    如果您有任何可以在编译时进行配置的东西,那么最好在运行时进行配置。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-06
      相关资源
      最近更新 更多