现在我们有了std :: array C样式数组还有什么用?


Answers:


60

除非我没有错过任何内容(我没有太严格地遵循标准的最新更改),否则仍然保留C样式数组的大多数用法。 std::array确实允许静态初始化,但仍然不会为您计算初​​始化次数。而且由于之前C样式数组的唯一真正用途std::array是用于静态初始化的表,因此:

MyStruct const table[] =
{
    { something1, otherthing1 },
    //  ...
};

使用常规beginend模板函数(在C ++ 11中采用)对它们进行迭代。不用说大小,编译器根据初始化程序的数量确定大小。

编辑:我忘记的另一件事:字符串文字仍然是C样式数组;即与类型char[]。我认为没有人会因为我们有而排除使用字符串文字std::array


7
您可以编写可变参数函数模板来构造数组,而无需指定长度。
2015年

2
使用C ++ 17 Class Template Deduction,可以自动推断出初始化程序的数量。例如,“ auto a = std :: array {1,2,3};”
Ricky65 '17

Nitpick:字符串文字的类型是const char[]
Bulletmagnet

30

不,要坦率地说。并以30个字符为单位。

当然,您需要C数组来实现 std::array,但这并不是用户想要C数组的真正原因。另外,不,std::array性能不比C数组低,并且可以选择进行边界检查访问。最后,对于任何C ++程序而言,完全依赖标准库是完全合理的(从某种意义上说,它就是标准库),如果您无法访问标准库,则编译器将不符合标准,并且问题被标记为“ C ++”,而不是“ C ++和那些因为感觉不合适而漏掉了一半规格的非C ++东西”。


1
嗯 如果您正在编写从另一种语言调用并需要将某些内容作为参数传递的C ++代码,该怎么办?
asveikau 2011年

3
独立的实现允许遗漏几乎所有标准库,并且仍然合规。但是,对于无法std::array在独立的C ++ 11实现中实现的编译器,我将有严重的怀疑。
2011年

11
C ++ 0x最终草案(文档N3092)第1.4.7节“定义了两种实现:托管和独立。对于托管实现,此国际标准定义了一组可用的库。独立实现是可以执行的一种。发生在没有操作系统的好处的情况下,并且具有一组实现定义的库,其中包括某些语言支持库”
。STL

24

似乎使用C数组比使用多维数组要容易std::array。例如,

char c_arr[5][6][7];

相对于

std::array<std::array<std::array<char, 7>, 6>, 5> cpp_arr;

同样由于C数组的自动衰减特性,c_arr[i]在上面的示例中将衰减到指针,您只需要将其余维度作为另外两个参数传递即可。我的观点是c_arr,复制并不昂贵。但是,cpp_arr[i]复制将非常昂贵。


1
但是,您可以array在不损失尺寸的情况下将多维传递给函数。并且,如果将其传递给函数模板,则该函数既可以推导维数又可以推导每个维数的大小,或者只是两个维数之一。这对于主要在任意维度上工作的科学模板库可能会很有趣。
塞巴斯蒂安·马赫

29
一个简单的方法template <typename T, int M, int N> using array2d = std::array<std::array<T, N>, M>;应该解决所有这些问题。
Miles Rout

6
你举的例子c_arr非常复制贵!您必须自己提供代码。它将衰变的指针与副本相比,更接近于std::array引用,如果需要,可以使用传递引用。
ChetS,2014年

1
@MilesRout从技术上讲std::size_t不是int吗?抱歉挑剔,但这将使它变得通用。
robbie

1
@ robbie0630是的,size_t如果您愿意的话,您可以做到,尽管我无法想象在许多情况下需要具有超过40亿行或列的数组。
Miles Rout

13

正如Sumant所说,内置C数组比使用多维数组要容易得多 std::array

嵌套时 std::array将变得非常难以阅读和不必要的冗长。

例如:

std::array<std::array<int, 3>, 3> arr1; 

相比

char c_arr[3][3]; 

此外,需要注意的是begin()end()size()所有返回无意义的值,当你窝std::array

由于这些原因,我创建了自己的固定大小的多维数组容器array_2darray_3d。它们类似于std::array但适用于2维和3维的多维数组。与内置多维数组相比,它们更安全并且性能也不差。我没有为尺寸大于3的多维数组提供容器,因为它们并不常见。在C ++ 0x中,可以创建可变参数模板版本,该版本支持任意数量的尺寸。

二维变量的示例:

//Create an array 3 x 5 (Notice the extra pair of braces) 

fsma::array_2d <double, 3, 5> my2darr = {{
    { 32.19, 47.29, 31.99, 19.11, 11.19},
    { 11.29, 22.49, 33.47, 17.29, 5.01 },
    { 41.97, 22.09, 9.76, 22.55, 6.22 }
}};

完整的文档可以在这里找到:

http://fsma.googlecode.com/files/fsma.html

您可以在此处下载该库:

http://fsma.googlecode.com/files/fsma.zip


4
固定大小的C样式数组很容易,但是如果您要更改尺寸,则会变得很复杂。例如,给定arr[x][y],您无法确定arr是数组数组,指针数组,指向数组的指针还是指向指针的指针。所有实现方式都是合法的,具体取决于您的需求。可能在大多数实际的多维数组用例中,需要在运行时确定大小。
基思·汤普森

我很乐意看到n维数组的可变模板实现!最好的元编程!
steffen 2014年

3
@steffen我几年前确实尝试过。您可以在这里查看它:code.google.com/p/fsma/source/browse/trunk/…。此处的测试用例:code.google.com/p/fsma/source/browse/trunk/…。我相信它可以做得更好。
Ricky65

5

实际上,C ++中可用的C样式数组的功能远不如真正的C数组。区别在于,在C中,数组类型可以具有运行时大小。以下是有效的C代码,但不能用C ++ C样式数组或C ++ array<>类型表示:

void foo(int bar) {
    double tempArray[bar];
    //Do something with the bar elements in tempArray.
}

在C ++中,您将不得不在堆上分配临时数组:

void foo(int bar) {
    double* tempArray = new double[bar];
    //Do something with the bar elements behind tempArray.
    delete[] tempArray;
}

这是无法实现的std::array<>,因为bar在编译时未知,因此需要使用C ++中的C样式数组或std::vector<>


尽管第一个示例可以相对轻松地用C ++表示(尽管需要new[]delete[]),但是如果没有以下条件,则不能在C ++中实现以下功能std::vector<>

void smoothImage(int width, int height, int (*pixels)[width]) {
    int (*copy)[width] = malloc(height*sizeof(*copy));
    memcpy(copy, pixels, height*sizeof(*copy));
    for(y = height; y--; ) {
        for(x = width; x--; ) {
            pixels[y][x] = //compute smoothed value based on data around copy[y][x]
        }
    }
    free(copy);
}

关键是,指向行数组的指针int (*)[width]不能使用C ++中的运行时宽度,这使得C ++中的任何图像处理代码都比C语言中的复杂得多。图像处理示例的典型C ++实现如下所示:

void smoothImage(int width, int height, int* pixels) {
    int* copy = new int[height*width];
    memcpy(copy, pixels, height*width*sizeof(*copy));
    for(y = height; y--; ) {
        for(x = width; x--; ) {
            pixels[y*width + x] = //compute smoothed value based on data around copy[y*width + x]
        }
    }
    delete[] copy;
}

此代码执行与上面的C代码完全相同的计算,但是无论使用了哪里的索引,都需要手动执行索引计算。对于2D情况,这仍然是可行的(即使有很多机会使索引计算错误)。但是,在3D情况下,它确实很讨厌。

我喜欢用C ++编写代码。但是,每当需要处理多维数据时,我都会真正问自己是否应该将代码的这一部分移至C。


7
应该注意的是,至少Clang和GCC支持C ++中的VLA。
Janus Troelsen 2014年

@JanusTroelsen,而且它们在支持哪些元素类型方面受到严格限制。
2015年

C11不会使VLA可选吗?如果是这样,那么我认为您的答案是误导性的。当C99是标准而非C11是正确的。
Z玻色子

1
@Zboson C99是C标准,并且有一些编译器可以实现其VLA功能(gcc例如)。C11使很多有趣的东西成为可选项,我不认为那是因为他们想取缔该功能。我倾向于认为这表明他们想降低编写完全符合标准的编译器的水平:VLA很难实现,而且很多代码也可以不这样做,因此对于某些新的编译器来说,这是有意义的平台,不必立即实施VLA。
cmaster-恢复莫妮卡

-1

可能std::array不是很慢。但是我使用简单的存储做了一些基准测试,并从std :: array;中读取了内容;请参阅以下基准测试结果(在W8.1,VS2013更新4上):

ARR_SIZE: 100 * 1000
Avrg = Tick / ARR_SIZE;

test_arr_without_init
==>VMem: 5.15Mb
==>PMem: 8.94Mb
==>Tick: 3132
==>Avrg: 0.03132
test_arr_with_init_array_at
==>VMem: 5.16Mb
==>PMem: 8.98Mb
==>Tick: 925
==>Avrg: 0.00925
test_arr_with_array_at
==>VMem: 5.16Mb
==>PMem: 8.97Mb
==>Tick: 769
==>Avrg: 0.00769
test_c_arr_without_init
==>VMem: 5.16Mb
==>PMem: 8.94Mb
==>Tick: 358
==>Avrg: 0.00358
test_c_arr_with_init
==>VMem: 5.16Mb
==>PMem: 8.94Mb
==>Tick: 305
==>Avrg: 0.00305

根据负号,我使用的代码在pastebin中(link

基准类代码在这里 ;

我对基准测试一无所知...我的代码可能有缺陷


6
没有基准代码或编译标志的基准结果?来吧,你可以做得更好。
R. Martinho Fernandes

FWIW,只有一小段代码已经表明基准存在严重缺陷。一个足够聪明的编译器会将整个事情变成了long test_arr_without_init() { return ARR_SIZE; }
R. Martinho Fernandes 2015年

那只是一个例子。我认为这没什么大不了的。我更改了代码以返回void,并在VS 2013中使用了/ O2 / Ot / Gl发行版。
K'Prime 2015年

删除返回值意味着编译器可以将整个过程变成void test_arr_without_init() {}现在。您确实需要跳过所有步骤,以确保要测量的代码就是要测量的代码。
R. Martinho Fernandes

-6
  1. 实施类似 std::array
  2. 如果您不想使用STL或不能
  3. 为了表现

27
告诉我,std::array性能将不如C数组。
Xeo

2
摘自Wikipedia:“不需要数组实现来进行边界检查。但是boost中的实现是对operator []而不是迭代器。” -因此operator []速度较慢。我没有看过实现,但是实现中的任何代码都可能妨碍优化程序。
Lou Franco

19
@Aaron McDaid:就像那样,仅在其中at(),不在。没有性能下降或代码膨胀,编译器旨在优化这种情况。而且,当然,添加检查功能是一种出色的调试工具,并且具有很大的优势。@Lou Franco:所有C ++代码都可能依赖于标准库-这就是它的用途。@Earlz:如果没有可用的STL,则它不是C ++,到此为止。operator[]std::vectorstd::array
小狗

6
@Earlz:C ++标准包含标准库。如果您不能使用该库,则该库不符合要求。其次,您必须拥有一个糟糕的编译器才能使用std::array大于等效的C数组。
小狗

5
@Earlz:“不完全符合”和“缺少规范中数百页的功能”之间有很大的区别。
小狗
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.