是否有正当理由在C++中使用 C 样式数组
Is there ever a valid reason to use C-style arrays in C++?
在 TR1 和 C++11 中的 std::vector
和 std::array
之间,动态和固定大小的数组都有安全的替代方案,它们知道自己的长度并且不会表现出可怕的指针/数组对偶性。
所以我的问题是,C++中是否有任何情况下必须使用 C 数组(除了调用 C 库代码(,或者完全"禁止"它们是否合理?
编辑:
谢谢大家的回复,但事实证明这个问题是重复的
现在我们有了 std::array C 样式数组还有什么用途?
所以我会指导大家去看那里。
[我不知道如何结束我自己的问题,但如果一个版主(或更多有投票的人(徘徊过去,请随时将其标记为重复并删除这句话。
起初我不想回答这个问题,但我已经担心这个问题会被 C 程序员或将C++编写为面向对象的 C 的人淹没。
真正的答案是,在惯用C++中,几乎从来没有理由使用 C 样式数组。即使使用 C 样式代码库,我也通常使用向量。你说这怎么可能?好吧,如果你有一个向量 v 和一个 C 风格的函数需要传入一个指针,你可以传递 &v[0](或者更好的是,v.data((,这是一回事(。
即使对于性能,您也很少能为 C 样式数组提供案例。std::vector 确实涉及双重间接,但我相信这通常会被优化掉。如果你不信任编译器(这几乎总是一个糟糕的举动(,那么你总是可以使用与上面相同的技术来获取紧循环的指针。对于 std::array,我相信包装器甚至更薄。
只有当你是一个了不起的程序员并且你确切地知道你为什么要这样做,或者一个了不起的程序员看到你的问题并告诉你这样做时,你才应该使用一个。如果你不是很棒并且你正在使用 C 风格的数组,那么你犯错误的可能性很高(但不是 100%(,
Foo data[] = {
是一种非常常见的模式。 元素可以很容易地添加到其中,并且data
数组的大小会根据添加的元素而增长。
使用 C++11,您可以使用以下std::array
复制以下内容:
template<class T, class... Args>
auto make_array( Args&&... args )
-> std::array< T, sizeof...(Args) >
{
return { std::forward<Args>(args)... };
}
但即使这样也不像人们想要的那么好,因为它不像 C 数组那样支持嵌套括号。
假设Foo
是struct Foo { int x; double y; };
. 然后使用 C 样式数组,我们可以:
Foo arr[] = {
{1,2.2},
{3,4.5},
};
同时
auto arr = make_array<Foo>(
{1,2.2},
{3,4.5}
};
不编译。 您必须为每一行重复Foo
:
auto arr = make_array<Foo>(
Foo{1,2.2},
Foo{3,4.5}
};
这是复制粘贴噪音,可能会妨碍代码的表现力。
最后,请注意,"hello"
是一个大小为 6 的const
数组。 代码需要知道如何使用 C 样式数组。
我对这种情况的典型反应是将 C 样式数组和 C++ std::array
s 转换为 array_view
s,一个由两个指针组成的范围,并对它们进行操作。 这意味着我不在乎我是否被输入了一个基于 C 或 C++ 语法的数组:我只关心我被输入了一个打包的数据元素序列。 这些也可以消耗std::dynarray
和std::vector
,而工作量很少。
它确实需要编写一个array_view
,或者从boost
那里偷一个,或者等待它被添加到标准中。
有时现有的代码库会迫使你使用它们
我最后一次需要在新代码中使用它们是在我做嵌入式工作的时候,标准库只是没有std::vector
或std::array
的实现。在一些较旧的代码库中,由于以前的开发人员做出的设计决策,您必须使用数组。
在大多数情况下,如果您使用 C++11 启动一个新项目,旧的 C 样式数组是一个相当糟糕的选择。这是因为相对于std::array
它们很难正确,这种困难是开发时的直接费用。这个C++常见问题解答条目很好地总结了我对这个问题的看法: http://www.parashift.com/c++-faq/arrays-are-evil.html
Pre-C++14:在某些(罕见(情况下,缺少像int这样的类型的初始化可以显着提高执行速度。特别是如果某些算法在执行过程中需要许多短寿命数组,并且机器没有足够的内存来预分配有意义和/或无法首先知道大小
C 样式数组在内存受限(并且受到严格限制(的嵌入式系统中非常有用。
这些数组允许在没有动态内存分配的情况下进行编程。 动态内存分配会生成碎片内存,在运行时的某个时间点,必须对内存进行碎片整理。 在安全关键系统中,碎片整理不能在具有关键时间的时间段内发生。
const
阵列允许将数据放入只读存储器或闪存中,超出宝贵的RAM区域。 数据可以直接访问,不需要任何额外的初始化时间,就像std::vector或std::array一样。
C 样式数组是将原始数据放入程序中的便捷工具。 例如,图像或字体的位图数据。 在没有硬盘驱动器或闪存驱动器的小型嵌入式系统中,必须直接访问数据。 C 样式数组允许这样做。
编辑 1:
此外,std::array 不能与不支持 C++11 或更高版本的编译器一起使用。
许多公司不想在项目启动后切换编译器。 此外,他们可能需要保留编译器版本以进行维护修复,以及当机构要求公司重现产品指定软件版本的问题时。
我今天只发现了一个原因:当您想要精确地知道数据块的大小并控制它以在一个巨大的数据块中对齐时。当您处理流处理器或流扩展(如 AVX 或 SSE(时,这很有用。控制将数据块分配给内存中一个巨大的单个对齐块是有用的。您的对象可以操作它们负责的段,当它们完成后,您可以以对齐的方式移动和/或处理巨大的矢量。
- 将包含C样式数组的对象初始化为成员变量(C++)
- C++中的高效循环缓冲区,它将被传递给C样式数组函数参数
- 当 std::move 与 C 样式数组或不移动对象时会发生什么
- 如何在谷歌模拟中匹配 C 样式数组
- 迭代器库中的 std::size() 不适用于传递给函数的 C 样式数组
- 解压缩 C 样式数组以及C++中的参数包
- 复制 C 样式数组和结构
- C++中循环和 C 样式数组的范围工作
- C++ - 移动具有固定大小的 c 样式数组成员的类的构造函数
- std::array与C样式数组用于连续内存
- 从原始指针(衰减的 C 样式数组)和大小生成范围::视图
- 不要声明 C 样式数组,而是使用 std::array<>
- 带C++的 C 样式数组?
- 如何从嵌套的 std::initializer_list 初始化 2D C 样式数组?
- 将 unique_ptr<std::vector> 与 c 样式数组结合使用
- 为什么我不能将 C 样式数组复制到 std::array?
- 函数需要 C 样式数组
- 键入 trait 以获取 std::array 或 C 样式数组的元素类型
- 何时需要删除 C 样式数组
- C++ C 样式数组作为语法错误的参数