2016-05-08 9 views
-1

I haben folgende StrukturMemset unter Verwendung von Vektor-Struktur zu initialisieren, die Array enthält

struct a { 
    int array[20] 
    int array2[45] 
} 

I Vektor dieser Struktur

vector<a> vec; 

Ich habe dieses vec verwendet geschaffen haben. Jetzt möchte ich initialisieren (setzen Sie alle Array-Werte innerhalb des Objekts im Vektorelement) auf Null. Wie kann ich es tun.?

+3

Was hat Sie daran gehindert, die Dokumentation 'std :: vector' zu lesen? Warum haben Sie sich entschieden, 'memset' zu verwenden? Was hast du versucht, nachdem du zu diesem Schluss gekommen bist? –

+0

@LightnessRacesinOrbit: std :: vector wird normalerweise den Standardkonstruktor für die Objekte aufrufen, die es enthält. Da diese Struktur nur eingebaute Typen sind, werden die Elemente nicht initialisiert. –

+0

@MartinBonner: Ja, ich bin mir dessen bewusst. Der OP muss einige Forschungen durchführen, um herauszufinden, wie man seine Elemente auf Null setzt.Diese Frage hat keinen Forschungsaufwand. Ich versuche, das OP dazu zu bringen, einige Untersuchungen durchzuführen. –

Antwort

0

Es stellt sich heraus, dass dies eine viel interessantere Frage ist, als es zuerst erscheint.

tl; dr: Wenn Sie einen C++ 03 oder späteren Compiler verwenden, müssen Sie nicht stören.

Sie müssen den Unterschied zwischen value initialization und default initialization verstehen. Im Grunde werden bei der Initialisierung des Wertes alle Elemente auf Null gesetzt, und bei der Standardinitialisierung bleiben sie alle in Ruhe. Wenn eines der Standardelemente der Struktur (rekursiv) einen benutzerdefinierten Standardkonstruktor hat, wird dies sowohl vom Wert als auch von der Standardinitialisierung aufgerufen.

Beachten Sie, dass Wert Initialisierung viel besser als memset auf Null, weil

  • ist, wird es Standardkonstruktoren nennen
  • Es wird Gleitkomma richtig initialisiert werden (auf 0,0) und Zeiger (NULL). Obwohl memset wird wahrscheinlich tun, dass auf Ihre Implementierung, es ist nicht garantiert.

Der normale Weg, um einen Vektor mit n Elemente zu erstellen, ist nur zu nennen:

std::vector<a> vec(n); 

C++ 98

diese

std::vector<a>::vector(size_type count, 
         const T& value = T(), 
         const Allocator& alloc = Allocator()); 

nennen Das Objekt value wird als Standardkonstrukt festgelegt ted, und Sie müssen die Elemente irgendwie initialisieren. Der beste Weg, dies zu tun, besteht darin, einen korrekt initialisierten Wert bereitzustellen, der kopiert werden soll. Also:

const static a azeroed; // Because this is static, it will be value initialized 
std::vector<a> vec(20,azeroed); 

Technische Anmerkung: Der C++ 98-Standard enthält nicht den Begriff „Wert der Initialisierung“, aber die Initialisierung von azeroed ist identisch.

C++ 03

demselben Vektor-Konstruktor aufgerufen wird, aber von C++ 03, das value Argument ist Wert initialisiert (so alles in den Garten rosig ist).

C++ 11

Der Anruf wird an

std::vector<a>::vector(size_type count); 

welcher Wert direkt die Elemente initialisiert.

C++ 14

Der Anruf wird an

std::vector<a>::vector(size_type count, const Allocator& alloc = Allocator()); 

(im Allgemeinen, sie erkannten, dass sie das Zuordner Argument vergessen hat). Es gibt einen sehr feinen Unterschied darin, dass die Elemente durch Aufrufe von Allocator::construct erstellt werden, und obwohl der Standardzuordner die Werte initialisiert, ist es möglich, eine benutzerdefinierte Version bereitzustellen, die dies nicht tut (siehe this answer). Wenn Sie das tun, wissen Sie fast sicher, was Sie tun.

Fazit

  • Sofern Sie einen echten C++ 98-Compiler verwenden, brauchen Sie nicht memset
  • zu nennen Providing ist einen explizit initialisiert Wert auf den Vektor Konstruktor legt Wert sicherer als Aufruf memset.
  • memset kann nicht integrierte Werte nicht richtig initialisieren (obwohl dies wahrscheinlich der Fall ist).
  • memset wird definitiv clobber alles wird ein richtiger Konstruktor. Dies ist eine große Wartungsgefahr. Wenn ein Wartungsprogrammierer die Struktur ändert, so dass es nicht mehr POD ist, wird der Code immer noch kompilieren - es wird nur die falsche Sache tun.
  • Es gibt eine Menge zu sagen, nur um die Struktur einen richtigen Standardkonstruktor geben, und dann müssen Sie sich keine Sorgen machen, ob eines der Elemente initialisiert werden, auch wenn Sie eine lokale Kopie haben.
+0

Das Problem dabei ist, dass, wenn Sie jemals die Typen ändern, möglicherweise die Struktur nicht mehr POD machen, wird dies einfach weiter Null setzen alles heraus, was ein kritischer Fehler sein könnte. Ich habe einmal eine solche in der Produktion gefunden, die jahrelang zu intermittierenden Abstürzen geführt hat und einen Kunden Tausende gekostet hat. Bevorzugen Sie eine typsichere Lösung in C++, insbesondere beim Teachen. –

+1

Das ist kein großartiges Beispiel. Die gezeigte Initialisierung führt dazu, dass alle Elemente null initialisierte Daten ohne den Aufruf von "memset" haben. – juanchopanza

+0

@juanchopanza: Kapitel und Vers bitte? Wenn die Definition der Struktur gegeben ist, initialisiert sie die Standardkonstruktion * nicht * null. (Oder habe ich das falsch verstanden?) –

1

Lesen der Kommentare, es gibt Code, den Sie nicht gezeigt haben, der Ihren Vektor bevölkerte. Jetzt möchten Sie den Speicher wiederverwenden, anstatt einen neuen zu erstellen, und Sie möchten ihn neu initialisieren.

Die kanonische Antwort für irgendeinen Algorithmus für irgendeinen C++ Behälter wird wahrscheinlich unter den Standardalgorithmen gefunden. In diesem Fall std::fill. Initialisiere deine Struktur wie du willst und kopiere sie in deinen Vektor. Entlang dieser Linien:

Wenn Sie versucht zu sagen, dass nicht schnell genug ist, überprüfen Sie. Ich denke, Sie werden feststellen, dass es ziemlich effizient ist. Der obige Code ist absolut sicher und funktioniert für jedes korrekt initialisierte Argument zu fill. Ich bezweifle, dass es schneller gemacht werden kann, ohne einige Annahmen über die Implementierung von a zu machen.