我遇到了一些使用以下方法分配二维数组的代码:
auto a = new int[10][10];
这在C ++中是否有效?我搜索了几本C ++参考书,但没有人提到这种方法。 通常我会手动完成分配,如下所示:
int **a = new int *[10];
for (int i = 0; i < 10; i++) {
a[i] = new int[10];
}
如果第一种方法有效,那么首选哪种方法?
答案 0 :(得分:19)
第一个例子:
auto a = new int[10][10];
将多维数组或数组数组分配为连续的内存块。
第二个例子:
int** a = new int*[10];
for (int i = 0; i < 10; i++) {
a[i] = new int[10];
}
这不是真正的多维数组。事实上,它是一个指针数组,需要两个间接来访问每个元素。
答案 1 :(得分:4)
表达式new int[10][10]
意味着分配一个包含10个int[10]
类型元素的数组,所以是的,这是一个有效的事情。
new返回的指针类型为int(*)[10]
;可以通过int (*ptr)[10];
声明一个这种类型的变量。
为了易读性,可能不应该使用该语法,并且应该优先使用示例中的auto
,或者使用typedef进行简化,如
using int10 = int[10]; // typedef int int10[10];
int10 *ptr;
答案 2 :(得分:1)
在这种情况下,对于小型数组,在堆栈上分配它们会更有效。甚至可能使用诸如std::array<std::array<int, 10>, 10>
之类的便利包装器。但是,一般来说,执行以下操作是有效的:
auto arr = new int[a][b];
其中a
是std::size_t
而b
是constexpr std::size_t
。这样可以提高分配效率,因为operator new[]
只需要调用sizeof(int) * a * b
作为参数,而不是a
调用operator new[]
sizeof(int) * b
作为论点。正如Galik在他的回答中所说,由于缓存一致性增加(整个阵列在内存中是连续的),因此还有可能缩短访问时间。
然而,我可以想象使用这样的东西的唯一原因是使用编译时大小的矩阵/张量,其中所有维度在编译时都是已知的,但如果它超过了堆,则在堆上分配堆栈大小。
一般情况下,最好编写自己的RAII包装类,如下所示(您还需要为高度/宽度添加各种访问器,以及实现复制/移动构造函数和赋值,但一般的想法在这里:
template <typename T>
class Matrix {
public:
Matrix( std::size_t height, std::size_t width ) : m_height( height ), m_width( width )
{
m_data = new T[height * width]();
}
~Matrix() { delete m_data; m_data = nullptr; }
public:
T& operator()( std::size_t x, std::size_t y )
{
// Add bounds-checking here depending on your use-case
// by throwing a std::out_of_range if x/y are outside
// of the valid domain.
return m_data[x + y * m_width];
}
const T& operator()( std::size_t x, std::size_t y ) const
{
return m_data[x + y * m_width];
}
private:
std::size_t m_height;
std::size_t m_width;
T* m_data;
};