什么是在C ++中复制数组的最快的可移植方式

时间:2010-09-13 09:27:06

标签: c++ arrays copy

这个问题一直困扰着我。我正在考虑的可能性是

  1. memcpy
  2. 的std ::复制
  3. cblas_dcopy
  4. 有没有人知道这三者的利弊是什么?其他建议也欢迎。

8 个答案:

答案 0 :(得分:26)

在C ++中,默认情况下应该使用std :: copy,除非你有充分的理由不这样做。原因是C ++类通过复制构造函数和复制赋值运算符以及列出的操作定义了自己的复制语义,只有std :: copy遵循这些约定。

memcpy()使用原始的逐字节数据副本(尽管可能会针对缓存行大小进行大量优化等),并忽略C ++复制语义(毕竟它是C函数......)。

cblas_dcopy()是一个专用函数,用于使用双精度浮点值的线性代数例程。它可能很擅长,但不应被视为通用目的。

如果您的数据是“简单”POD类型结构数据或原始基本类型数据,则memcpy可能会尽可能快。同样可能,std :: copy将在这些情况下进行优化以使用memcpy,因此您永远不会知道其中的区别。

简而言之,使用std :: copy()。

答案 1 :(得分:1)

在大多数情况下,memcpy将是最快的,因为它是最低级别,可以在给定平台上的机器代码中实现。 (但是,如果你的数组包含非平凡的对象,memcpy可能无法正确思考,因此坚持使用std :: copy可能更安全)

然而,这一切都取决于stdlib在给定平台上植入的程度等。由于标准没有说明操作必须有多快,因此无法在“便携式”中知道因为什么是最快的。

分析您的应用程序将显示给定平台上的禁食,但只会告诉您有关测试平台的信息。

但是,当您对应用程序进行概要分析时,您很可能会发现问题出在您的设计中,而不是您选择的数组复制方法。 (例如,为什么需要复制大型数组才能匹配?)

答案 2 :(得分:1)

memcpy ,但是,如果您的数组包含非平凡的对象,请坚持使用 std :: copy

答案 3 :(得分:1)

memcpy可能是复制连续内存块的最快方法。这是因为它可能会针对您的特定硬件进行高度优化。它通常作为内置编译器函数实现。

话虽如此,非POD C ++对象不太可能是连续的,因此使用memcpy复制C ++对象数组可能会给您带来意想不到的结果。复制C ++对象的数组(或集合)时,std::copy将使用对象自己的复制语义,因此适用于非POD C ++对象。

cblas_dcopy看起来像是用于特定库的副本,并且在不使用该库时可能没用。

答案 4 :(得分:1)

使用std :: copy,除非分析显示您在执行其他操作时所需的好处。它尊重C ++对象封装,调用复制构造函数和赋值运算符,并且实现可以包括其他内联优化,例如,如果在编译时已知大小并且太小而不能对memcpy()进行外联函数调用证明函数调用开销。 (有些系统可能有memcpy宏做出类似的确定,但一般来说,C ++编译器会更深入地了解优化在功能上是等价的。)

FWIW /在旧的Linux机箱上我很方便,GCC没有做任何惊人的优化,但是bit / type_traits.h确实允许程序轻松指定std :: copy是否应该通过memcpy():< / p>

 * Copyright (c) 1997
 * Silicon Graphics Computer Systems, Inc.
 *
 * Permission to use, copy, modify, distribute and sell this software
 * and its documentation for any purpose is hereby granted without fee,
 * provided that the above copyright notice appear in all copies and            
 * that both that copyright notice and this permission notice appear            
 * in supporting documentation.  Silicon Graphics makes no                      
 * representations about the suitability of this software for any               
 * purpose.  It is provided "as is" without express or implied warranty.        
 ...                                                                            

/*                                                                              
This header file provides a framework for allowing compile time dispatch        
based on type attributes. This is useful when writing template code.            
For example, when making a copy of an array of an unknown type, it helps        
to know if the type has a trivial copy constructor or not, to help decide       
if a memcpy can be used.

The class template __type_traits provides a series of typedefs each of
which is either __true_type or __false_type. The argument to
__type_traits can be any type. The typedefs within this template will
attain their correct values by one of these means:
    1. The general instantiation contain conservative values which work
       for all types.
    2. Specializations may be declared to make distinctions between types.
    3. Some compilers (such as the Silicon Graphics N32 and N64 compilers)
       will automatically provide the appropriate specializations for all
       types.

EXAMPLE:

//Copy an array of elements which have non-trivial copy constructors
template <class _Tp> void
  copy(_Tp* __source,_Tp* __destination,int __n,__false_type);
//Copy an array of elements which have trivial copy constructors. Use memcpy.
template <class _Tp> void
  copy(_Tp* __source,_Tp* __destination,int __n,__true_type);

//Copy an array of any type by using the most efficient copy mechanism
template <class _Tp> inline void copy(_Tp* __source,_Tp* __destination,int __n) {
   copy(__source,__destination,__n,
        typename __type_traits<_Tp>::has_trivial_copy_constructor());
}
*/

答案 5 :(得分:0)

我必须认为其他人会调用memcpy()。话虽如此,我无法相信会有任何明显的差异。

如果它对你真的很重要,那就编写所有三个并运行一个分析器,但最好还是考虑可读性/可维护性,异常安全等等......(并且在你使用它时编写汇编程序插入代码) ,而不是你可能会看到差异)

你的程序是否有线程?

而且,最重要的是,你是如何对数组进行分类的? (它是一个数组)和它有多大?

答案 6 :(得分:0)

我已经做了一个小型基准测试(VS 2018 Preview,MKL 2017 Update 4)来比较import calendar # if you have a list with year, month, day # for example this new1 = [2018, 6, 19] print(calendar.weekday(*new1)) # important to put * before new1 # output # 1 和顺序版本的memcpy,发现它们在cblas_?copy上的速度同样快和float

答案 7 :(得分:-3)

只需简介您的应用程序。您可能会发现复制不是最慢的部分。