Benutzerdefinierte Zeigertypen und container / allocator typedefs

8

C ++ - Standardcontainer und -zuordner stellen typedefs für den vom Container verwendeten Zeigertyp bereit, d. h .:

%Vor%

Der tatsächliche Zeigertyp, der zum Erstellen des typedef verwendet wird, wird über std::allocator_traits

festgelegt %Vor%

Da jeder Container auch ein value_type typedef hat, ist der Zweck von pointer typedef vermutlich für eine seltsame Situation, in der der verwendete Zeigertyp etwas anderes als value_type* ist. Ich habe nie persönlich einen Anwendungsfall für so etwas gesehen, aber ich nehme an, das Normenkomitee wollte die Möglichkeit bieten, benutzerdefinierte Pointer-Typen mit Containern zu verwenden.

Das Problem ist, dass dies mit den Definitionen für die Funktionen in std::allocator_traits nicht übereinstimmt. Insbesondere haben wir in std::allocator_traits die Funktion construct , die wie folgt definiert ist:

%Vor%

... welches nur a.construct(p, std::forward<Args>(args)...)

aufruft

Beachten Sie jedoch, dass diese Funktion keinen benutzerdefinierten Zeigertyp vorsieht. Der Parameter p ist ein einfacher nativer Zeiger.

Also, warum ist die Definition dieser Funktion nicht ungefähr wie folgt:

%Vor%

Es sieht so aus, als ob Container, die std::allocator_traits<Alloc>::construct verwendeten, fehlschlagen würden, wenn sie mit einem Allocator verwendet würden, der einen benutzerdefinierten Zeigertyp definiert.

Also, was ist hier los? Oder missverstehe ich den Zweck von pointer typedefs an erster Stelle?

    
Siler 14.02.2015, 22:54
quelle

1 Antwort

6

Diese Dichotomie ist zielgerichtet und stellt kein Problem dar. Die construct -Memberfunktion wird typischerweise wie folgt implementiert:

%Vor%

i.e. Es wird an das Placement new weitergeleitet, das wiederum diese Signatur hat:

%Vor%

Sie benötigen also letztendlich einen "echten" Zeiger, um die Platzierung neu anzulegen. Um den Typ des Objekts, das konstruiert werden soll, zu vermitteln, ist es nur sinnvoll, diese Information im Zeigertyp (z. B. U* ) mitzuliefern.

Für die Symmetrie wird destroy auch in Form eines tatsächlichen Zeigers formuliert und normalerweise wie folgt implementiert:

%Vor%

Der Hauptanwendungsfall für den "extravaganten Zeiger" ist das Platzieren von Objekten in einem gemeinsamen Speicher. Eine Klasse mit dem Namen offset_ptr wird normalerweise für diesen Zweck verwendet, und ein Zuordner kann erstellt werden, um Speicher, auf den von offset_ptr verwiesen wird, zuzuweisen und freizugeben. Und somit funktioniert der allocator_traits und allocator allocate und deallocate Traffic in pointer anstelle von value_type* .

Es stellt sich also die Frage: Wenn du pointer hast und T* brauchst, was machst du?

Ich kenne zwei Techniken, um ein T* von einem pointer p

zu erstellen

1. std::addressof(*p);

Wenn Sie eine pointer p dereferenzieren, muss dies zu einem lvalue gemäß dem Standard führen. Es wäre jedoch nett, diese Anforderung lockern zu können (z. B. in Betracht ziehen, dass pointer eine Proxy-Referenz wie vector<bool>::reference zurückgibt). std::addressof wird angegeben, um T* an einen beliebigen lvalue zurückzugeben:

%Vor%

2. to_raw_pointer(p); // where:

%Vor%

Dies ruft pointer 's operator->() auf, die entweder direkt ein T* zurückgeben oder auf etwas weiterleiten, das entweder direkt oder indirekt ein T* zurückgibt. Alle pointer types sollten operator->() unterstützen, auch wenn auf bool verwiesen wird. Ein Nachteil dieser Technik ist, dass derzeit operator->() nicht aufgerufen werden muss, es sei denn die pointer ist dereferenzierbar. Diese Einschränkung sollte in der Norm aufgehoben werden.

In C ++ 14 kann der Rückgabetyp der zweiten Überladung (also eigentlich beide Überladungen), bequem durch auto ersetzt werden.

Wenn Sie T* haben und ein pointer erstellen möchten, haben Sie kein Glück. Es gibt keinen portablen Weg, um in diese Richtung zu konvertieren.

Beachten Sie auch dieses tangential verwandte LWG-Problem zum Rückgabetyp vector::data() member function. Er ist zwischen value_type* , pointer und zurück aufgetaucht und ist derzeit (und absichtlich) value_type* .

    
Howard Hinnant 14.02.2015, 23:46
quelle

Tags und Links