我有一个函数foo(int[] nums)
,我理解它基本上等同于foo(int* nums)
。在foo
内部,我需要将nums
指向的数组内容复制到int[10]
范围内声明的某些foo
中。我理解以下内容无效:
void foo (int[] nums)
{
myGlobalArray = *nums
}
复制阵列的正确方法是什么?我应该像这样使用memcpy:
void foo (int[] nums)
{
memcpy(&myGlobalArray, nums, 10);
}
还是应该使用for循环?
void foo(int[] nums)
{
for(int i =0; i < 10; i++)
{
myGlobalArray[i] = nums[i];
}
}
我缺少第三种选择吗?
答案 0 :(得分:61)
是的,第三个选项是使用C ++构造:
std::copy(&nums[0], &nums[10], myGlobalArray);
使用任何理智的编译器,它:
memcpy()
),答案 1 :(得分:22)
Memcpy可能会更快,但你更有可能在使用它时犯了错误。 这可能取决于优化编译器的智能程度。
但您的代码不正确。它应该是:
memcpy(&myGlobalArray, nums, 10 * sizeof(int) );
答案 2 :(得分:5)
一般来说,最糟糕的情况是在未优化的调试版本中,其中memcpy
未内联,并且可能执行额外的健全/断言检查,相当于少量额外指令与for循环。 / p>
然而,memcpy
通常很好地实现了利用内在函数等内容,但这会因目标架构和编译器而异。 <{1}}不太可能比for循环实现更糟糕。
人们经常会对memcpy以字节为单位的大小进行绊倒,他们会写下这样的内容:
memcpy
您可以通过使用可以进行某种程度反思的语言功能来保护自己,即:根据数据本身而不是您对数据的了解来做事,因为在通用功能中,您通常不会&# 39;对数据一无所知:
// wrong unless we're copying bytes.
memcpy(myGlobalArray, nums, numNums);
// wrong if an int isn't 4 bytes or the type of nums changed.
memcpy(myGlobalArray, nums, numNums);
// wrong if nums is no-longer an int array.
memcpy(myGlobalArray, nums, numNums * sizeof(int));
请注意,您并不想要&#34;&amp;&#34;面对&#34; myGlobalArray&#34;因为数组会自动衰减到指针;你实际上正在复制&#34; nums&#34;到内存中指向myGlobalArray [0]的指针的地址。
(编辑说明:我的错误&#39; d void foo (int* nums, size_t numNums)
{
memcpy(myGlobalArray, nums, numNums * sizeof(*nums));
}
我的意思是int[] nums
但我决定添加C array-pointer-equivalence混乱帮助没人,现在它int nums[]
:))
在对象上使用int *nums
可能很危险,请考虑:
memcpy
这是复制不是POD(普通旧数据)的对象的错误方法。 f1和f2现在都有一个std :: string,它认为它拥有&#34;你好&#34;。其中一个在破坏时会崩溃,他们都认为它们拥有包含42个整数的相同向量。
C ++程序员的最佳实践是使用struct Foo {
std::string m_string;
std::vector<int> m_vec;
};
Foo f1;
Foo f2;
f2.m_string = "hello";
f2.m_vec.push_back(42);
memcpy(&f1, &f2, sizeof(f2));
:
std::copy
注意每个Remy Lebeau 或自C ++ 11以来
std::copy(nums, nums + numNums, myGlobalArray);
这可以使编译时决定做什么,包括使用std::copy_n(nums, numNums, myGlobalArray);
或memcpy
并尽可能使用SSE /向量指令。另一个优点是,如果你这样写:
memmove
稍后更改Foo以包含struct Foo {
int m_i;
};
Foo f1[10], f2[10];
memcpy(&f1, &f2, sizeof(f1));
,您的代码将会中断。如果您改为写:
std::string
编译器会切换你的代码来做正确的事情而不需要任何额外的工作,你的代码更具可读性。
答案 3 :(得分:1)
为了提高性能,请使用memcpy(或等效物)。它是高度优化的平台特定代码,用于快速分流大量数据。
为了可维护性,请考虑您正在做什么 - for循环可能更易读,更容易理解。 (得到一个记忆错误是通往崩溃或更糟糕的快速途径)
答案 4 :(得分:1)
基本上,只要您处理POD类型(Plain Ol'数据),例如int,unsigned int,指针,仅数据结构等等,您就可以安全地使用mem *。
如果您的数组包含对象,请使用for循环,因为可能需要=运算符以确保正确分配。
答案 5 :(得分:1)
一个简单的循环大约要快10-20个字节,甚至更少(这是一个单行+分支,请参见OP_T_THRES
),但是对于较大的循环,memcpy
则更快,更可移植。 >
此外,如果要复制的内存量恒定,则可以使用memcpy
让编译器决定使用哪种方法。
侧面说明:当您复制大量大于memcpy
大小的数据时,OP_T_THRES
使用的优化可能会大大降低程序在多线程环境中的运行速度,因为此调用的指令并不当多个线程正在访问同一内存时,此类指令的原子性和推测性执行以及缓存行为会表现不佳。最简单的解决方案是不在线程之间共享内存,而仅在最后合并内存。无论如何,这是一个很好的多线程实践。