在 c++11 中复制常量大小数组的最简洁方法

Posted

技术标签:

【中文标题】在 c++11 中复制常量大小数组的最简洁方法【英文标题】:Cleanest way to copy a constant size array in c++11 【发布时间】:2012-09-01 22:32:23 【问题描述】:

我经常发现自己想要复制具有恒定大小的数组的内容,我通常只写一些类似的内容:

float a[4] = 0,1,2,3;
float b[4];

for(int i=0; i<4; i++)
    b[i]=a[i];

最近,我正在编写一个用于教育目的的线性微积分库,我想知道是否有更好的方法。

我首先想到的是使用 memcpy:

memcpy(b, a, sizeof(float) * 4);

但这对我来说似乎很像 c 并且容易出错。我喜欢在编译时出现错误,这对于具有非平凡复制构造函数的数据类型,或者如果我忘记与 sizeof(datatype) 相乘,这可能会变得很难看。

由于我正在编写一个我将大量使用的数学库,因此性能对我来说非常重要。今天的编译器是否足够聪明,能够理解第一个示例只是复制一块内存并将其优化为与第二个解决方案一样高效?

也许标准库中有一个函数可以帮助我? c++11有什么新东西吗?还是我应该只创建一个宏或模板函数?

【问题讨论】:

“但这对我来说似乎很像 c 并且容易出错” - 它有什么容易出错的地方?你知道大小,你知道内存是有效的......不会发生错误。如果您正在处理 POD 类型,我将始终使用 memcpy 【参考方案1】:

C++03 方式

使用std::copy():

float a[4] = 0,1,2,3;
float b[4];

std::copy(a,a + 4, b);

这几乎是最干净的了。

C++11 方式

std::copy(std::begin(a), std::end(a), std::begin(b));

如果可以使用 std::array

使用std::array,您只需做简单的分配:

std::array<float,4> a = 0,1,2,3;
auto b = a;

【讨论】:

为了避免在更改数组大小时悄悄地破坏,我建议std::copy(a, a + sizeof(a)/sizeof(a[0]), b);。更好的是,将 sizeof() 垃圾包裹在宏中——或者更好的是,使用函数模板代替:template &lt;typename T, size_t N&gt; size_t size((T&amp;)[N]) return N; @j_random_hacker:在 C++11 中,std:copy(std::begin(a), std::end(a), std::begin(b)) @GManNickG:所以他们最终在 C++11 中添加了泛型 begin()end()?精彩的! (而且如此明显的事情...... C++03 怎么会错过它?!)我可以停止在我的自制的周围推车:) 有趣。我也不知道你现在可以在数组上使用std::begin/end。 :) 反对者愿意发表评论吗?如果我不知道哪里出了问题,就很难改进。【参考方案2】:

如果您使用std::array 而不是内置数组(您应该这样做),它会变得非常简单。复制一个数组就和复制任何其他对象一样。

std::array<float,4> a = 0,1,2,3;
std::array<float,4> b = a;

【讨论】:

+1 这显然是 C++11 的方式(而不是 std::copy() 方法,因为它们使用运行时大小,因此使用比编译时更不容易优化大小,这是首先使用数组(而不是vector)的关键 @Walter:实际上,Mysticial 和 hjbabs 提出的使用std::copy 的方法都使用编译时间常数。因此它们可以以完全相同的方式进行优化。 @BenjaminLindley 你没明白我的意思。 std::copy() 函数模板接受大小作为运行时常量。如果该数字在编译时已知,那么编译器可以进行一些优化。对于std::array&lt;&gt;::operator=,这是在编译时说明的:没有需要优化(或不优化)与运行时大小相关的代码。我不喜欢依赖编译器来做这些类型的优化。 我有点困惑。这个问题是关于 C 风格的数组。为什么使用 std::arrays 的解决方案?对我来说,这绝对不应该是这个问题的规范答案。 @user650261:问题不在于 C 风格的数组。它是关于恒定大小的数组。拥有恒定大小数组的一种方法是使用 c 样式的数组。 OP 在提出问题之前显然没有意识到的另一种方式是std::array。事实证明,std::array 几乎在所有方面都非常适合此目的。特别是,它在解决 OP 真正关心的问题方面要好得多。【参考方案3】:
#include <algorithm>
std::copy_n(a, 4, b)

【讨论】:

对于数组来说这不是最有效的方法,因为元素的数量是运行时参数而不是编译时参数。 @Walter:你是对的,std::array 应该用于固定大小的数组【参考方案4】:

对 C++03(以及 C)解决方案感兴趣 - 始终使用包含数组的结构而不是单独的数组:

struct s  float arr[5]; ;

结构体默认是可复制的。

它在 C++11 中的等价物,已经提到过,std::array&lt;float,5&gt;;

【讨论】:

关于 c++03 结构包装的好点。我需要更好地记住这一点:) 谢谢,这是我从谷歌寻找的信息。因为关于 std/boost::array 的分配没有太多说明。它的默认生成,因此标准规定了行为。但是关于聚合的章节很难用普通的法律术语来阅读。【参考方案5】:

以下方法也适用于普通数组以及 std:array。

float a[4] = 0,1,2,3;
float b[4];

std::copy(std::begin(a), std::end(a), b);

【讨论】:

请注意为什么要投反对票。这行得通,它确实是 C++ 中的首选方式,也适用于通常的数组,我一直都在使用它。 @Shitai Shah,无论是否喜欢它都很难看,而且容易出错。 @CodingLab,不同意。我的代码到处都是这个,如果您使用的是现实世界中丰富的 c 样式数组,这是一个很好的解决方案。

以上是关于在 c++11 中复制常量大小数组的最简洁方法的主要内容,如果未能解决你的问题,请参考以下文章

C ++创建一个向量大小的数组,然后将向量复制到C样式数组中[重复]

c语言04

C语言数组寻址

C语言字符串常量,字符数组占内存大小问题?

C ++ 11分段错误试图将数组(<算法>)动态复制到向量中

C ++ 11数组按引用传递,函数中没有大小