模板非类型参数和分配数组内存



我正在阅读的一本书中有一个示例类,用于从头到尾解释概念:

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++规则(我忘记了)禁止在堆栈上声明多维数组,因此这种方法令人兴奋?

我试图理解在他们的例子中使用非类型模板参数的优点是什么。

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

如你所见,你的数组直接是一个成员,而不是由指针间接指向的。

T mCells[WIDTH][HEIGHT];

但是说它在堆栈或堆上是不正确的,因为实际上数组是你的对象的一部分,它在哪里取决于你的对象在哪里以及如何分配。如果对象是在堆上分配的,那么它的数组子对象也会在堆上分配,如果整个对象都在堆栈上,那么数组也会在堆上分配。

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

。但是有一个新的数组既慢,更容易出错(即它应该被删除等)。

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

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

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

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

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

的速度。在这种情况下,由于Gameboard可能会停留很长时间,因此没有必要这样做。实际上,std::vector<std::vector<GamePiece>> mCells会比手动数组更好。

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

不,这是允许的。但是像普通数组一样,维数必须在编译时已知。

"我试图理解在他们的例子中使用非类型模板参数的优势是什么。"

这是一个人为的例子。

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

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

关于动态内存分配,我不太喜欢这种方法

因为根本不需要更多的动态分配,即使您在堆栈上创建实例。

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

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

除了上述原因之外,动态分配还会在运行时带来性能冲击,这对于性能关键应用程序(例如游戏框架渲染引擎)来说是不必要的。

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

相关内容

  • 没有找到相关文章

最新更新