Подтвердить что ты не робот

Каков самый быстрый переносимый способ копирования массива в С++

Этот вопрос беспокоил меня в течение некоторого времени. Возможности, которые я рассматриваю,

  • memcpy
  • станд:: копия
  • cblas_dcopy

Кто-нибудь знает, что за плюсы и минусы с этими тремя? Другие предложения также приветствуются.

4b9b3361

Ответ 1

В С++ вы должны использовать std:: copy по умолчанию, если у вас нет веских оснований для этого. Причина в том, что классы С++ определяют собственную семантику копирования с помощью конструктора копирования и оператора присваивания копий, а также из перечисленных операций только std:: copy соблюдает эти соглашения.

memcpy() использует сырую, байт-мутную копию данных (хотя, вероятно, сильно оптимизирована для размера строки кэша и т.д.) и игнорирует семантику копирования С++ (это функция C, в конце концов...).

cblas_dcopy() - специализированная функция для использования в линейных алгоритмах с использованием значений с плавающей запятой двойной точности. Вероятно, это стоит того, но не следует считать общей целью.

Если ваши данные являются "простыми" структурными данными типа POD или необработанными данными основного типа, memcpy, вероятно, будет так же быстро, как вы можете получить. Скорее всего, std:: copy будет оптимизирован для использования memcpy в этих ситуациях, поэтому вы никогда не узнаете разницу.

Короче говоря, используйте std:: copy().

Ответ 2

Используйте std:: copy, если профилирование не показывает вам нужную выгоду в противном случае. Он чтит инкапсуляцию объектов С++, вызывая конструкторы копирования и операторы присваивания, а реализация может включать в себя другие встроенные оптимизации, такие как отказ от вызова функции вне сети для memcpy(), если размер известен во время компиляции и слишком мал для оправдывайте служебные данные вызова функции. (Некоторые системы могут иметь макросы memcpy, которые делают подобные определения, но в целом компилятор С++ будет иметь более полное представление о том, какие оптимизации функционально эквивалентны.)

FWIW/на старом ящике Linux, мне удобно, GCC не делает каких-либо впечатляющих оптимизаций, но bits/type_traits.h позволяет программе легко указать, должна ли std:: copy проходить через memcpy():

 * 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());
}
*/

Ответ 3

В большинстве случаев memcpy будет самым быстрым, так как он является самым низким уровнем и может быть реализован в машинный код на данной платформе. (однако, если ваш массив содержит нетривиальные объекты, memcpy может не делать правильные мысли, поэтому может быть безопаснее придерживаться std:: copy)

Однако все зависит от того, насколько хорошо имплантируется stdlib на данной платформе и т.д. Поскольку стандарт не говорит, насколько быстрыми должны быть операции, нет никакого способа узнать в "переносном", так как будет быстрее.

Профилирование вашего приложения покажет поститься на данной платформе, но расскажет вам только о тестовой платформе.

Однако при профилировании приложения вы, скорее всего, обнаружите, что проблемы находятся в вашем дизайне, а не в выборе метода копирования массива. (Например, почему вам нужно копировать большие массивы, чтобы они совпадали?)

Ответ 4

Просто профайл приложения. Вероятно, вы обнаружите, что копирование не является самой медленной частью этого.

Ответ 5

memcpy, однако, если ваш массив содержит нетривиальные объекты, придерживайтесь std:: copy.

Ответ 6

Мне нужно подумать, что остальные вызовут memcpy(). Сказав, что я не могу поверить, что будет какая-то заметная разница.

Если это действительно важно для вас, введите все три кода и запустите профилировщик, но лучше рассмотреть такие вещи, как читаемость/ремонтопригодность, исключение и т.д. (и код вставки ассемблера, пока вы на нем, а не то, что вы, вероятно, увидите разницу)

Прописана ли ваша программа?

И, самое главное, как вы объявляете свой массив? (что это массив) и насколько он велик?

Ответ 7

memcpy, вероятно, самый быстрый способ скопировать непрерывный блок памяти. Это связано с тем, что он, вероятно, будет сильно оптимизирован для вашего конкретного оборудования. Он часто реализуется как встроенная функция компилятора.

Сказав это, и объект не POD С++ вряд ли будет смежным, и поэтому копирование массивов объектов С++ с использованием memcpy может привести к неожиданным результатам. При копировании массивов (или наборов) объектов С++ std::copy будет использовать семантику собственного экземпляра объекта и поэтому подходит для использования с объектами не POD С++.

cblas_dcopy выглядит как копия для использования с определенной библиотекой и, вероятно, мало используется, если вы не используете эту библиотеку.