36 votes

Le programmeur C ++ doit-il éviter memset?

J'ai entendu dire que les programmeurs c ++ devraient éviter memset,

 class ArrInit {
    //! int a[1024] = { 0 };
    int a[1024];
public:
    ArrInit() {  memset(a, 0, 1024 * sizeof(int)); }
};
 

Donc, en considérant le code ci-dessus, si vous n'utilisez pas memset, comment pouvez-vous créer un [1..1024] rempli de zéro? Quel est le problème avec memset en C ++?

Merci.

49voto

Charles Salvia Points 28661

En C ++, std::fill ou std::fill_n peut constituer un meilleur choix, car il est générique et peut donc fonctionner à la fois sur des objets et sur des POD. Cependant, memset fonctionne sur une séquence d'octets brute et ne doit donc jamais être utilisé pour initialiser des non-POD. Quoi qu'il en soit, les implémentations optimisées de std::fill peuvent utiliser en interne la spécialisation pour appeler memset si le type est un POD.

23voto

UncleBens Points 24580

L'initialisation à zéro devrait ressembler à ceci:

class ArrInit {
    int a[1024];
public:
    ArrInit(): a() { }
};

À l'aide de memset, il ya un couple de façons de rendre l'utilisation plus robuste (comme avec toutes les fonctions): éviter de coder en dur la taille du tableau et le type:

memset(a, 0, sizeof(a));

Pour plus de contrôles de compilation, il est également possible de faire en sorte qu' a est en effet un tableau (donc sizeof(a) aurait du sens):

template <class T, size_t N>
size_t array_bytes(const T (&)[N])  //accepts only real arrays
{
    return sizeof(T) * N;
}

ArrInit() { memset(a, 0, array_bytes(a)); }

Mais pour les non-types de caractère, j'imagine que la seule valeur que vous souhaitez utiliser pour remplir avec est 0, et zéro-initialisation devrait déjà être disponible d'une manière ou d'une autre.

10voto

AndreyT Points 139512

Quel est le problème avec memset en C++ est la plupart du temps la même chose qui ne va pas avec memset C. memset remplit la mémoire de la région avec un physique de zéro bits, tandis que, dans les faits, pratiquement 100% des cas, vous devez remplir un tableau avec le zéro logique des valeurs de type correspondant. En langage C, memset n'est garanti que pour initialiser correctement la mémoire pour les types d'entiers (et sa validité pour tous les types d'entiers, plutôt que de simplement char types, est relativement récente garantie ajouté à C spécification de langage). Il n'est pas garanti pour bien mettre à zéro toutes les valeurs à virgule flottante, il n'est pas garanti pour produire le bon null-pointeurs.

Bien sûr, le ci-dessus peut être vu comme trop pédant, puisque les normes et les conventions de l'actif sur la plate-forme donnée peut (et plus certainement), étendre le champ d'application de l' memset, mais je voudrais encore vous proposons de suivre le rasoir d'Occam principe ici: ne comptez pas sur toutes les autres normes et des conventions, à moins que vous vraiment, vraiment. Langage C++ (ainsi que C) offre plusieurs langues-niveau de fonctionnalités qui vous permettent d'initialiser en toute sécurité votre regroupement d'objets avec un bon zéro des valeurs de type approprié. D'autres réponses déjà mentionné ces fonctionnalités.

8voto

jcoder Points 14982

Il est "mauvais" parce que vous n'êtes pas la mise en œuvre de votre intention.

Votre intention est de définir chaque valeur dans le tableau à zéro et ce que vous avez programmé est l'établissement d'une zone de la mémoire brute à zéro. Oui, les deux choses qui ont le même effet mais c'est plus clair pour tout simplement écrire le code à zéro à chaque élément.

Aussi, il est probablement plus efficace.

class ArrInit
{
public:
    ArrInit();
private:
    int a[1024];
};

ArrInit::ArrInit()
{
    for(int i = 0; i < 1024; ++i) {
        a[i] = 0;
    }
}


int main()
{
    ArrInit a;
}

La compilation avec visual c++ 2008 32 bits avec des optimisations tourné sur la compile de la boucle -

; Line 12
    xor eax, eax
    mov ecx, 1024				; 00000400H
    mov edi, edx
    rep stosd

Qui est à peu près exactement ce que les memset serait susceptible de les compiler, de toute façon. Mais si vous utiliser memset il n'y a pas de place pour le compilateur d'effectuer des optimisations, alors que par écrit de votre intention, il est possible que le compilateur pourrait effectuer d'autres optimisations, par exemple en remarquant que chaque élément est plus tard, à quelque chose d'autre avant elle est utilisée pour l'initialisation peut être optimisé, ce qui probablement ne pouvait pas faire presque aussi facilement que si vous aviez utilisé memset.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X