在C++中声明数组

Declaring arrays in C++

本文关键字:数组 声明 C++      更新时间:2023-10-16

我是C++新手,目前正在自己一本书中学习它。这本书似乎说有几种数组取决于你如何声明它。我想动态数组和静态数组之间的区别对我来说很清楚。但我不明白 STLstd::array类和静态数组之间的区别。

STLstd::array变量声明为:

std::array < int, arraySize > array1;

而静态数组变量声明为:

int array1[arraySize];

两者之间有根本区别吗?还是只是语法,两者基本相同?

std::array<>只是围绕 C 样式数组的轻量级包装器,带有一些额外的漂亮接口成员函数(如beginend等)和typedefs,大致定义为

template<typename T, size_t N>
class array
{
public:
T _arr[N];
T& operator[](size_t);
const T& operator[](size_t) const;
// other member functions and typedefs
}

一个根本的区别是,前者可以按值传递,而对于后者,您只能传递指向其第一个元素的指针,或者可以通过引用传递它,但不能将其复制到函数中(除非通过std::copy或手动)。

一个常见的错误是假设每次将 C 样式数组传递给函数时,由于数组衰减到指针,您会丢失其大小。这并不总是正确的。如果通过引用传递它,则可以恢复其大小,因为在这种情况下没有衰减:

#include <iostream>
template<typename T, size_t N>
void f(T (&arr)[N]) // the type of arr is T(&)[N], not T*
{
std::cout << "I'm an array of size " << N;
}
int main()
{
int arr[10];
f(arr); // outputs its size, there is no decay happening
}

住在科里鲁

这两者之间的主要区别很重要。

除了 STL 为您提供的好方法之外,当将std::array传递给函数时,没有衰减。这意味着,当你在函数中接收std::array时,它仍然是一个std::array,但是当你将一个int[]数组传递给一个函数时,它实际上衰减为一个int*指针,数组的大小就会丢失。

这种差异是主要的。一旦你失去了数组大小,代码现在很容易出现很多错误,因为你必须手动跟踪数组大小。sizeof()返回指针类型的大小,而不是数组中元素的数量。这会强制您使用process(int *array, int size)等接口手动跟踪数组大小。这是一个不错的解决方案,但容易出错。

请参阅Bjarne Stroustroup的指南:

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rp-run-time

这可以通过更好的数据类型来避免,std::array是为许多其他 STL 类而设计的。

作为旁注,除非有充分的理由使用固定大小的数组,否则std::vector作为连续内存数据结构可能是更好的选择。

std::array和C样式数组相似:

  • 它们都存储一个连续的对象序列
  • 它们都是聚合类型,因此可以使用聚合初始化进行初始化
  • 它们的大小在编译时是已知的
  • 它们不使用动态内存分配

std::array的一个重要优点是它可以按值传递,并且不会像 C 样式数组那样隐式衰减到指针。

在这两种情况下,数组都是在堆栈上创建的。

但是,STL 的std::array类模板与第二种情况的"原始"类 C 数组语法相比具有一些优势:

int array1[arraySize];

例如,使用std::array您有一个典型的 STL 接口,其中包含size(可用于查询数组的元素计数)、frontbackat等方法。

您可以在此处找到更多详细信息。

两者之间有根本区别吗? 还是只是语法,两者基本相同?

原始 c 样式数组(内置数组)与std::array有许多差异。

从参考文档中可以看到,有许多操作不适用于原始数组:

例如:元素访问

at()
front()
back()
data()

std::array的基础数据类型仍然是原始数组,但用"语法糖">装饰(如果这应该是您的关注点)。

std::array<>

和C 样式数组的主要区别在于前者是包裹后者的类。 该类具有begin()end()方法,这些方法允许std::array对象作为参数轻松地传递给需要迭代器的 STL 算法(请注意,C 样式数组也可以通过非成员std::begin/std::end方法)。 第一个指向数组的开头,第二个指向数组末尾之外的一个元素。 您可以在其他 STL 容器中看到此模式,例如std::vectorstd::mapstd::set等。

STLstd::array的另一个优点是它有一个size()方法,可以让你获取元素计数。要获得 C 样式数组的元素计数,您必须编写sizeof(cArray)/sizeof(cArray[0]),那么stlArray.size()看起来不是更具可读性吗?

您可以在此处获得完整的参考资料:

http://en.cppreference.com/w/cpp/container/array

通常你应该更喜欢std::array<T, size> array1;而不是T array2[size];,尽管底层结构是相同的。

主要原因是std::array总是知道它的大小。你可以调用它的 size() 方法来获取大小。而当你使用C风格的数组(即你所说的"内置数组")时,你总是必须将大小传递给使用该数组的函数。如果您以某种方式弄错了,可能会导致缓冲区溢出,并且该函数尝试读取/写入不再属于数组的内存。这不会发生在std::array,因为大小总是清晰的。

IMO,

  • 优点:它很高效,因为它不会比内置固定数组使用更多的内存。

  • 缺点:内置固定数组的std::array是一种稍微笨拙的语法,您必须显式指定数组长度(编译器不会从初始值设定项为您计算它)。