2010-09-13 4 views
16

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

  1. тетсру
  2. станд :: скопировать
  3. cblas_dcopy

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

ответ

23

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

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

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

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

Одним словом, используйте std :: copy().

+0

Кажется, что 'std :: copy' скорее использует' std :: memmove', потому что диапазоны позволяют перекрываться (на одном конце). – visitor

+0

@visitor: Наверное, правда. Но я уверен, что memmove() вызывает memcpy(), если он определяет, что диапазоны не перекрываются (простая арифметика указателя). –

+0

Я видел реализацию memmove, которая просто делает копию назад, если перекрытие вызовет проблемы. – doron

0

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

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

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

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

0

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

0

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

+3

хорошей реализации 'станд :: copy' может быть быстрее, даже для базовых объектов; 'memcpy' должен иметь дело с произвольными выравниваниями адресов, но' std :: copy' знает выравнивание во время компиляции. –

+4

Ужасно много советов по производительности на C++, похоже, включают в себя такие классификаторы, как «хорошая реализация ... может быть быстрее». Сколько из этих гипотетических оптимизаций действительно было реализовано где угодно, когда-либо? – Porculus

+0

@Mike Seymour; Вы понимаете, что говорили о копировании массива, т. Е. Непрерывного блока памяти, содержащего объекты? –

0

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

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

Ваша программа имеет резьбу?

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

0

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

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

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

+0

Почему вы предполагаете, что 'std :: copy' будет медленнее, чем' memcpy'? – jalf

1

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

FWIW/на старом Linux-поле у ​​меня есть, GCC не делает любые зрелищные оптимизации, но бит/type_traits.h делает позволяет программу легко определить, следует ли станд :: копия упадет до тетсра():

* 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()); 
} 
*/ 
Смежные вопросы