2017-07-07 4 views
0

J'ai vu la différence pointée dans la réponse acceptée dans What is the difference between memmove and memcpy? et il a dit memmove might be very slightly slower than memcpy.Performance de memmove comparé à memcpy deux fois?

Nous pouvons implémenter une alternative pour memmove en procédant comme suit: allouer un tampon temporaire, puis memcpy deux fois (src -> tmp, tmp -> dest). Ma question est: quelle est la voie la plus rapide, memmove ou l'alternative?

+0

Cela dépend de la machine cible et de l'implémentation. –

+4

Les données de copie sont lentes. Copier les données * deux fois * sera plus lent. Ce 'memmove' * pourrait être plus lent que' memcpy' parce qu'il est capable de gérer la mémoire qui se chevauche, mais 'memmove' copie toujours les données * une fois *. –

+1

profil sur la plate-forme que vous êtes intéressé par les horaires pour. Cependant, les chances de vous écrire un meilleur memmove que Memmove semble improbable. – xaxxon

Répondre

4

De http://en.cppreference.com/w/cpp/string/byte/memmove

En dépit d'être spécifié « comme si » un tampon temporaire est utilisé, les mises en œuvre effective de cette fonction n'encourent pas la charge de la double copie ou de la mémoire supplémentaire. Pour un petit compte, il peut charger et écrire des registres; pour les plus gros blocs, une approche courante (glibc et bsd libc) est de copier les octets vers l'avant depuis le début du tampon si la destination commence avant la source, et inversement depuis la fin sinon, avec une retombée sur std :: memcpy Il n'y a pas de chevauchement du tout.

Par conséquent, le surdébit est vraisemblablement un couple de branches conditionnelles. Ne vaut pas la peine de s'inquiéter pour les gros blocs.

Cependant, il est utile de rappeler que std::memcpy est une fonction «magique», étant la seule façon légale de faire un cast entre deux types dissemblables.

En C++, ce qui est illégal (comportement non défini):

union { 
    float a; 
    int b; 
} u; 

u.a = 10.0; 
int x = u.b; 

C'est légal:

float a = 10.0; 
int b; 
std::memcpy(std::addressof(b), std::addressof(a), size(b)); 

et fait ce que vous attendez le syndicat à faire si vous étiez un programmeur C .

1

std::memmove « peut être très légèrement plus lent questd::memcpy » (souligné), car il doit d'abord vérifier si la source et les plages cibles se chevauchent. En interne, c'est juste quelques comparaisons de pointeurs; après avoir fait cela, s'il n'y a pas de chevauchement ou si la cible commence en dessous de la source, elle appelle std::memcpy; sinon, il appelle une variante de std::memcpy qui copie de la fin vers le début. En résumé, seulement différence est cette comparaison initiale; Une fois cela fait, c'est comme std::memcpy. Pas besoin de ce tampon supplémentaire et de tout copier deux fois.

0

Memcpy est généralement plus rapide car il ne suppose pas que la destination et la source peuvent se chevaucher.

Donc, si vous essayez d'utiliser memcpy pour copier la chaîne abcd à partir d'un emplacement X-X+2 il est possible d'obtenir un tel résultat

X: A B C D 

après memcpy

X+2 A B A A 

tout memmove vous garantira que rien n'est perdu, car il utilise un tampon intermédiaire pour stocker la chaîne d'origine.D'autre part, vous pouvez utiliser le qualificateur restrict pour la source et la destination et ainsi vous pouvez dire à memmove que la source et la destination ne se chevauchent pas, et comme ce memmove pourrait choisir un autre algorithme plus rapide au cas où vous utilisez ce qualificatif.

Pour plus de détails, voir here.