515 Stimmen

Welche Verwendungszwecke gibt es für "Platzierung neu"?

Hat irgendjemand hier jemals die "Platzierung neu" von C++ verwendet? Wenn ja, wofür? Für mich sieht es so aus, als ob es nur auf memory-mapped Hardware nützlich wäre.

3voto

Keith A. Lewis Punkte 743

Siehe die Datei fp.h im xll-Projekt unter http://xll.codeplex.com Es löst das Problem der "ungerechtfertigten Anbiederung an den Compiler" für Arrays, die ihre Dimensionen gerne mit sich herumtragen.

typedef struct _FP
{
    unsigned short int rows;
    unsigned short int columns;
    double array[1];        /* Actually, array[rows][columns] */
} FP;

3voto

Hier ist die Killer-Anwendung für den C++ In-Place-Konstruktor: Ausrichten auf eine Cache-Zeile, sowie andere Potenzen von 2 Grenzen. Hier ist meinen ultraschnellen Algorithmus zur Ausrichtung von Zeigern auf beliebige Potenzen von 2 Grenzen mit 5 oder weniger Einzelzyklusanweisungen :

/* Quickly aligns the given pointer to a power of two boundary IN BYTES.
@return An aligned pointer of typename T.
@brief Algorithm is a 2's compliment trick that works by masking off
the desired number in 2's compliment and adding them to the
pointer.
@param pointer The pointer to align.
@param boundary_byte_count The boundary byte count that must be an even
power of 2.
@warning Function does not check if the boundary is a power of 2! */
template <typename T = char>
inline T* AlignUp(void* pointer, uintptr_t boundary_byte_count) {
  uintptr_t value = reinterpret_cast<uintptr_t>(pointer);
  value += (((~value) + 1) & (boundary_byte_count - 1));
  return reinterpret_cast<T*>(value);
}

struct Foo { Foo () {} };
char buffer[sizeof (Foo) + 64];
Foo* foo = new (AlignUp<Foo> (buffer, 64)) Foo ();

Zaubert das nicht ein Lächeln auf Ihr Gesicht (:-). I C++1x

1voto

Ich habe auch eine Idee. C++ hat Null-Grenzkosten-Prinzip . Ausnahmen folgen jedoch nicht diesem Prinzip, so dass sie manchmal mit einem Compilerschalter ausgeschaltet werden.

Schauen wir uns dieses Beispiel an:

#include <new>
#include <cstdio>
#include <cstdlib>

int main() {
    struct A {
        A() {
            printf("A()\n");
        }
        ~A() {
            printf("~A()\n");
        }
        char data[1000000000000000000] = {}; // some very big number
    };

    try {
        A *result = new A();
        printf("new passed: %p\n", result);
        delete result;
    } catch (std::bad_alloc) {
        printf("new failed\n");
    }
}

Wir weisen hier eine große Struktur zu und prüfen, ob die Zuweisung erfolgreich war, und löschen sie.

Aber wenn wir Ausnahmen ausgeschaltet haben, können wir nicht verwenden, Try-Block, und nicht in der Lage, new[] Fehler zu behandeln.

Wie können wir das also tun? Hier ist wie:

#include <new>
#include <cstdio>
#include <cstdlib>

int main() {
    struct A {
        A() {
            printf("A()\n");
        }
        ~A() {
            printf("~A()\n");
        }
        char data[1000000000000000000] = {}; // some very big number
    };

    void *buf = malloc(sizeof(A));
    if (buf != nullptr) {
        A *result = new(buf) A();
        printf("new passed: %p\n", result);
        result->~A();
        free(result);
    } else {
        printf("new failed\n");
    }
}
  • Einfaches malloc verwenden
  • Prüfen Sie, ob sie auf C-Art fehlgeschlagen ist
  • Wenn es erfolgreich ist, verwenden wir die Platzierung neuer
  • Manueller Aufruf des Destruktors (wir können nicht einfach delete aufrufen)
  • free aufrufen, da wir malloc aufgerufen haben

UPD @Useless schrieb einen Kommentar, der mir die Existenz von neu(nothrow) die in diesem Fall verwendet werden sollte, aber nicht die Methode, die ich zuvor geschrieben habe. Bitte verwenden Sie nicht den Code, den ich zuvor geschrieben habe. Entschuldigung.

0voto

Ich habe noch eine Idee (sie gilt für C++11).

Betrachten wir das folgende Beispiel:

#include <cstddef>
#include <cstdio>

int main() {
    struct alignas(0x1000) A {
        char data[0x1000];
    };

    printf("max_align_t: %zu\n", alignof(max_align_t));

    A a;
    printf("a: %p\n", &a);

    A *ptr = new A;
    printf("ptr: %p\n", ptr);
    delete ptr;
}

Mit dem C++11-Standard gibt GCC das Folgende aus Ausgabe :

max_align_t: 16
a: 0x7ffd45e6f000
ptr: 0x1fe3ec0

ptr nicht richtig ausgerichtet ist.

Mit C++17 Standard und weiter, GCC gibt die folgende Ausgabe :

max_align_t: 16
a: 0x7ffc924f6000
ptr: 0x9f6000

ptr richtig ausgerichtet ist.

Wie ich weiß, unterstützte der C++-Standard vor der Einführung von C++17 keine übermäßig ausgerichteten neuen Strukturen, und wenn Ihre Struktur eine Ausrichtung hat, die größer als max_align_t können Sie Probleme bekommen. Um dieses Problem in C++11 zu umgehen, können Sie Folgendes verwenden aligned_alloc .

#include <cstddef>
#include <cstdlib>
#include <cstdio>
#include <new>

int main() {
    struct alignas(0x1000) A {
        char data[0x1000];
    };

    printf("max_align_t: %zu\n", alignof(max_align_t));

    A a;
    printf("a: %p\n", &a);

    void *buf = aligned_alloc(alignof(A), sizeof(A));
    if (buf == nullptr) {
        printf("aligned_alloc() failed\n");
        exit(1);
    }
    A *ptr = new(buf) A();
    printf("ptr: %p\n", ptr);
    ptr->~A();
    free(ptr);
}

ptr es ausgerichtet in diesem Fall.

max_align_t: 16
a: 0x7ffe56b57000
ptr: 0x2416000

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X