2016-06-20 14 views
1

Ich versuche, meine eigene Allocator zu schreiben, die in STL verwendet werden kann. So weit kann ich fast erfolgreich beenden, aber mit einer Funktion habe ich mein Problem:Synonym-Funktionsaufruf für :: new ((void *) p) T (Wert);

Die Allocator in STL verwendet wird, soll die Funktion construct [Beispiel aus einem Standard-Allocator new & mit delete] bieten:

// initialize elements of allocated storage p with value value 
void construct (T* p, const T& value) 
{ 
    ::new((void*)p)T(value); 
} 

I Ich stecke fest, wie ich dies mit meiner eigenen Funktion umschreiben kann, die das Schlüsselwort new ersetzt und es mit value initialisiert.

Diese Funktion construct zum Beispiel ist in diesem Code verwendet: fileLines.push_back(fileLine);

wo

MyVector<MyString>  fileLines; 
MyString    fileLine; 

mein Dies sind typedefs, wo ich meine eigene Allocator verwenden:

template <typename T> using MyVector = std::vector<T, Allocator<T>>; 
using MyString = std::basic_string<char, std::char_traits<char>, Allocator<char>>; 

Ich bin verwirrt, weil hier wird zB pointer bis T zugeteilt [wenn ich es richtig verstanden habe] MySstring.

Habe ich es richtig verstehe, dass der Zeiger - zugeteilt durch new-10 Bytes haben wird, wenn value123456789 ist, und dann wird die bereitgestellte value auf den neuen Zeiger kopiert?

Meine Frage:

Wie die eine Zeile Code mit meiner eigenen Funktion neu zu schreiben? Für mich die schwierig Punkt ist, wie man die Länge von value [die jede Art haben kann] in Reihenfolge kann ich die Länge des zugewiesenen Blockes und wie man kopieren es in der Reihenfolge funktioniert es für alle möglichen Typen T ?

Antwort

5

Der new Operator in der construct Funktion nicht überhaupt etwas vergeben, es ist ein Platzierung neuer Aufruf, der einen bereits zugewiesenen Teil des Speichers nimmt (die zuvor in gewisser Weise zugeordnet haben muss worden, und mindestens so groß als sizeof(T)) und initialisiert es als ein T Objekt, indem es den Konstruktor T aufruft und so tut, als ob der Speicher, auf den zeigt, ein T Objekt ist.

+1

Dies ist für die meisten Leute zunächst ziemlich verwirrend. In diesem speziellen Kontext bedeutet "Platzierung neu" eigentlich "Aufruf eines Klassenkonstruktors": C++ fehlt eine dedizierte Syntax zum Aufrufen eines Konstruktors auf einer Speicheradresse (anders als beim Aufrufen eines * Destruktors *, der eine dedizierte Syntax hat , über 'p-> ~ T()'). Die Standard-Überladung von Placement new bewirkt jedoch genau das. –

1

::new int(7) ruft den Standard new Operator, bekommt etwas Speicher groß genug für eine int und konstruiert ein int mit dem Wert 7 darin.

::new(ptr) int(7) nimmt ein void*ptr genannt, und konstruiert ein int mit dem Wert 7 darin. Dies wird "Platzierung neu" genannt.

Der wichtige Teil ist, was im zweiten Absatz fehlt. Es erstellt keinen Platz, sondern konstruiert ein Objekt in einem vorhandenen Raum.

Es ist wie wenn man sagt ptr->T::T()ptr->int::int(7), wo wir den Konstruktor „nennen of int on the memory location of ptr , except ptr-> T :: T() or ptr-> int :: int (7) are not valid syntaxes. Placement new` ist die Art und Weise ausdrücklich zu nennen ein Konstruktor in C++.

Ähnlich ptr->~T() oder ptr->~int() die destructor an dem Objekt bei ptr (jedoch befindet nennen, gibt es keine ~int so ist, dass ein Fehler vorliegt, es sei denn, int eine Vorlage oder abhängigen Typ ist, in welchem ​​Fall es ist ein Pseudo-Destruktor und der Aufruf wird ignoriert anstatt einen Fehler zu erzeugen.)

Es ist sehr selten, dass Sie construct von der Standardimplementierung in einem Zuordner ändern möchten. Sie könnten dies tun, wenn Ihr Zuordner die Erstellung von Objekten verfolgen und die Informationen zu ihren Argumenten anhängen möchte, ohne den Konstruktor zu verändern. Aber das ist ein Eckfall.