我正在阅读的一本书中有一个示例类,用于从头到尾解释概念:
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++规则(我忘记了)禁止在堆栈上声明多维数组"
不,这是允许的。但是像普通数组一样,维数必须在编译时已知。
"我试图理解在他们的例子中使用非类型模板参数的优势是什么。"
这是一个人为的例子。
假设您想要创建一个任意精度的整数类。精度越高,需要的空间就越大。这个类可以被频繁地创建和销毁,就像一个普通的整数变量一样。如果数据是动态分配的,则会变慢。通过使用模板参数指定所需的精度,可以创建所需大小的常规数组作为类的成员。当类被放到堆栈中时,数组也会被放到堆栈中,这样会更快。
在不提及您给出的特定示例和来源的情况下:
关于动态内存分配,我不太喜欢这种方法
因为根本不需要更多的动态分配,即使您在堆栈上创建实例。
我不明白为什么你不想在堆上动态分配内存?
我经常在小型嵌入式系统上工作,有时我甚至没有动态内存管理的可能性(或者我不想承担开销)。对于这样的系统,并且您事先非常清楚您可以/想要实际拥有的大小,这是您想要用于目标特定平台实现的非常好的配置抽象。
除了上述原因之外,动态分配还会在运行时带来性能冲击,这对于性能关键应用程序(例如游戏框架渲染引擎)来说是不必要的。
总之:
如果您有任何可以在编译时配置的东西,那么最好在编译时配置,而不是在运行时配置。