Frage Kann ich die Größe eines mit "new type [n]" erstellten Arrays in C ++ angeben?


Mit C ++ 11 möchte ich ein Array von Booleans erstellen und es sofort löschen

bool *mymap = new bool[n];

n ist variabel.

Wird der Speicher, der vom Array belegt ist, bereits gelöscht? Wenn nicht, gibt es einen besseren Ansatz, um das Array zu löschen, als eine Schleife über alle Elemente zu verwenden, indem jedes einzeln auf false gesetzt wird?

Ich überlegte, std: memset () zu verwenden, aber das erfordert, dass ich die Größe des Arrays kenne. Jetzt könnten Anfänger sagen: Einfach, die Größe ist n * sizeof (bool). Aber ich kaufe das nicht. Der Compiler könnte entscheiden, sie anders zu packen, sogar als Bits zu packen, oder?

Gibt es also eine Möglichkeit, die Größe des Arrays sauberer zu bestimmen? Ich stelle mir vor, es könnte eine Funktion std: arraysize () geben, die einfach den Speicherplatz des zugewiesenen Arrays im Speicher zurückgibt. Immerhin müssen diese Informationen zur Laufzeit irgendwie beibehalten werden, oder ein Löschaufruf würde nicht wissen, wie viel freigegeben werden soll, richtig?


8
2017-08-14 10:26


Ursprung


Antworten:


Die Antwort auf die spezifische Frage ist nein, Sie können die Länge des Arrays, auf das gezeigt wird, nicht bestimmen mymap. Die Sprache bietet dazu einfach keinen Mechanismus.

Wenn Sie jedoch nur sicherstellen möchten, dass alle Elemente des Arrays festgelegt sind false, dann müssen Sie nur Wert initialisieren:

bool* mymap = new bool[n]();
//                       ^^

Leider funktioniert das nur für Null-ähnliche Werte für integrierte Typen. Es gäbe keine gleichwertige Möglichkeit, alle Werte auf zu setzen true.


10
2017-08-14 10:45



Sie können es nicht auf eine normale Art und Weise tun. Verschiedene Compiler unterstützen jedoch verschiedene Hacks, z.

#if defined(_MSC_VER) || ( defined(__GNUC__) && defined(_WIN32) )
      // a dirty MSVC and MinGW hack
      size_t Size = _msize( mymap );
#elif defined(__GNUC__)
      // a dirty glibc hack  
      size_t Size = malloc_usable_size( mymap );
#else
   #error Implement for any other compiler
#endif      

Aber das sind echte Hacks, also pass auf.

Apropos, std::vector kann Ihnen helfen, Ihr Problem innerhalb des Standards zu lösen.


6
2017-08-14 10:49



Nein, kannst du nicht, weil es kein Array ist. mymap ist nur ein normaler Zeiger auf einige Heapspeicher, und wenn Sie die Größe wissen müssen, müssen Sie entweder selbst den Überblick behalten oder einen Standardcontainer wie std::vector.

Oh, und wenn Sie eine generische Variante von memset lesen über std::fill.


4
2017-08-14 10:28



Nein, der Compiler kann nicht entscheiden, sie zu packen, außer dass die Größe der Region ist n * sizeof(bool) Wenn Sie es auf andere Weise tun, würde die Fähigkeit, einzelne Array-Mitglieder zu adressieren, nicht mehr funktionieren mymap[x] (das ist das gleiche wie *(mymap + x)).

In diesem Fall ist der Vorschlag eines Anfängers der richtige.


4
2017-08-14 10:30



Sie können dies versuchen:

bool *mymap = new bool[n] ();

Dies setzt jedoch auf false und Sie können nicht auf diese Weise festlegen true.


2
2017-08-14 11:33



Nehmen wir an, dass der Compiler beschließt, anders zu packen.

Annahme 1: Der Compiler packt einige Bits zu einem Byte zusammen. Wenn Sie die Adresse eines einzelnen Elements im Array verwenden, hat es den Typ bool. Da der Compiler (im Allgemeinen) nicht abziehen kann, was Sie mit dieser Adresse tun werden (z. B. Übergabe an eine Funktion, die ihn an eine Lib weiterleitet, ...), kann Bit-Packing innerhalb eines Bytes nicht wirklich passieren. Andernfalls muss der Compiler das entsprechende Bit aus seiner gepackten Region maskieren und es irgendwo als echten Bool bewegen.

Annahme 2: Der Compiler verwendet mehr als sizeof (bool) für einen Bool-Wert. Sehr unwahrscheinlich - denn dann wäre die Größe von (bool) einfach größer. Zeigermanipulationen sind weiterhin möglich und bei Bit-Arrays muss noch eine andere magische Logik implementiert werden.

Annahme 3: Der Compiler verwendet unterschiedliche Größen für die verschiedenen Felder des Arrays - noch unwahrscheinlicher. Die erforderlichen Verwaltungsinformationen sind einfach zu groß.

Aus diesen 3 Gedanken würde ich sagen, dass die einfache Lösung die beste ist. Nur um sicher zu sein, jetzt und die ganze Zukunft Ihres Programms, schreiben Sie einen kleinen Unit-Test, der genau das testet (zB die Adresse des ersten Wertes holen, ihn auf einen Zeiger eines Typs werfen, der die gleiche Größe wie bool hat, Berechne die Adresse von Element n, wandle diese Adresse zurück in einen Zeiger von bool, schreibe dort etwas und vergleiche mit dem Array-Zugriff). Dann erhalten Sie eine Benachrichtigung, wenn sich etwas ändert - aber ich bezweifle es.


Randnotiz - natürlich kann der Compiler immer mehr Speicher als nötig reservieren. Aber trotzdem hat das Array diese Größe (es ist nur in einem größeren Speicherbereich platziert).


2
2017-08-14 12:40



In blankem C ++ ist das nicht möglich. Sie werden jedoch dazu ermutigt (und sollten es wirklich tun), eine Klasse zu verwenden, um den Speicher trotzdem zu verwalten.

In C ++ 98 können Sie entweder a verwenden boost::scoped_array oder ein std::vector (obwohl für bool Vielleicht bevorzugen Sie eine std::vector<char>).

In C ++ 11 sollten Sie einen Austausch in Betracht ziehen boost::scoped_array durch std::unique_ptr<bool[]>.

Das Problem ist bis dahin, abgesehen von std::vector, keiner von ihnen kennt die Größe des Arrays, das sie enthalten; sie behandeln nur die Erinnerung.

In C ++ 14 erscheint ein neuer Anwärter: std::dynarray. Es ist eine abgespeckte Version von std::vector deren Größe nicht dynamisch geändert werden kann. Kurz gesagt, genau das, was Sie wollen: nur das Array und seine Länge, kein Overhead.

Wenn dein bevorzugter Compiler / Toolchain dies nicht unterstützt dynarray Sie können es jedoch einfach selbst implementieren:

template <typename T>
class dynarray {
public:
    // methods go here.
private:
    size_t size;
    std::unique_ptr<T[]> array;
}; // class dyn_array

2
2017-08-14 13:06