2016-01-20 10 views
21

Ich habe eine Funktion, die einen Zeiger und eine Länge zurückgibt, und ich möchte std::string::assign(pointer, length) aufrufen. Muss ich einen Sonderfall (Aufruf clear) machen, wenn die Länge Null ist und der Zeiger nullptr sein kann?Ist es zulässig, nullptr an std :: string :: assign zu übergeben?

Der C++ Standard sagt:

21.4.6.3 basic_string::assign 

basic_string& assign(const charT* s, size_type n); 
Requires: s points to an array of at least n elements of charT. 

Was also, wenn n Null ist? Was ist ein Array von null Zeichen und wie zeigt man darauf? Ist es gültig zu nennen

s.assign(nullptr, 0); 

oder ist es nicht definiertes Verhalten?

Die Implementierung von libstdC++ scheint den Zeiger s nicht zu dereferenzieren, wenn die Größe n Null ist, aber das ist kaum eine Garantie.

+0

Auf eine verwandte Anmerkung würde 'char a [4]; s.assign (s + 4, 0); "legal sein? Das scheint eine vernünftige Interpretation von "array of length 0" zu sein und könnte in der Praxis plausibel erscheinen. –

Antwort

19

Pedicanly, ein nullptr erfüllt nicht die Anforderungen, auf ein Array der Größe >=0 zu zeigen, und daher garantiert der Standard nicht das Verhalten (es ist UB).

Auf der anderen Seite würde die Implementierung den Zeiger nicht dereferenzieren, wenn n Null ist, weil der Zeiger zu einem Array der Größe Null sein könnte, und Dereferenzierung eines solchen Zeigers hätte undefiniertes Verhalten. Außerdem wäre das nicht nötig, weil nichts kopiert wird.

Die obige Argumentation nicht bedeutet, dass es in Ordnung ist, die UB zu ignorieren. Aber wenn es keinen Grund gibt, s.assign(nullptr, 0) zu verbieten, dann könnte es besser sein, den Wortlaut des Standards zu "Wenn n größer als Null ist, dann zeigt s auf ..." zu ändern.Ich kenne keinen guten Grund, es abzulehnen, aber ich kann auch nicht versprechen, dass es keinen guten Grund gibt.

Beachten Sie, dass eine Überprüfung Zugabe kaum kompliziert ist:

s.assign(ptr ? ptr : "", n); 

Was eine Reihe von Null-Zeichen ist

Dies ist: new char[0]. Arrays mit automatischem oder statischem Speicher dürfen keine Größe null haben.

+6

Implementierungen dürfen die Gültigkeit des Zeigers überprüfen. Prüfen, ob Zeiger auf zugewiesenen Speicher zeigt oder sogar einfache Prüfung '__debug_assert (cstr! = Nullptr)' kann in jeder konformen Implementierung existieren –

+0

@Revolver_Ocelot dort kann und wie gesagt, der Standard garantiert nicht das Verhalten. Ich würde erwarten, dass jede Implementierung, die den Zeiger überprüft, dies nur tut, wenn der Zeiger dereferenziert wird. – user2079303

+0

Ich bevorzuge 'clear()', wenn ich einen Sonderfall für die Länge null machen muss. – Bulletmagnet

12

Nun, wie Sie darauf hinweisen, sagt der Standard „s auf ein Array ...“. Ein Nullzeiger zeigt nicht auf ein Array mit einer beliebigen Anzahl von Elementen. Nicht einmal 0 Elemente. Beachten Sie auch, dass s zeigt auf „eine Anordnung von mindestens n Elemente ...“. Es ist also klar, dass, wenn n Null ist, Sie immer noch einen legitimen Zeiger auf ein Array übergeben können.

Insgesamt ist die std::string API gegen Nullzeiger auf charT nicht gut geschützt. Sie sollten also immer sicherstellen, dass die von Ihnen übergebenen Zeiger nicht null sind.

9

Ich bin nicht sicher, warum eine Implementierung würde dereferenzieren jeder Zeiger auf ein Array, dessen Länge als Null vorgesehen ist.

Das heißt, ich auf der Seite der Vorsicht irren würde. Man könnte argumentieren, dass Sie nicht den Standards Anforderung entsprechen:

21.4.6.3 basic_string :: zuordnen

Benötigt: s auf ein Array von mindestens n Elemente von charT

weil nullptr nicht auf Array zeigt.

Technisch gesehen ist das Verhalten nicht definiert.

5

Vom Standard (2.14.7) [lex.nullptr]:

Der Zeiger wörtliche ist das Schlüsselwort nullptr. Es ist ein Prvalue des Typs std::nullptr_t. [Hinweis: std::nullptr_t ist ein einzigartiger Typ, der weder ein Zeigertyp Typ noch ein Zeiger auf ein Element ist ...]

std::nullptr_t implizit als pro 4.10.1 auf jede Art von Null-Zeiger umgewandelt werden kann [ conv.ptr]. Unabhängig vom Typ des Nullzeigers bleibt die Tatsache, dass er auf nichts zeigt.

Somit erfüllt es nicht die Anforderung, dass s auf ein Array von mindestens n Elementen von char zeigt.

Es scheint, undefiniertes Verhalten zu sein.

Interessanterweise, nach this answer, der C++ 11 Standard klar angegeben, dass s kein Nullzeiger im basic_string Konstruktor sein darf, aber dieser Wortlaut wurde seitdem entfernt.

+2

Wahr, aber ein nullptr_t kann implizit in einen Nullzeiger eines beliebigen Typs umgewandelt werden, einschließlich char *. Das Problem ist, dass der resultierende Nullzeiger nicht auf irgendwas zeigt, nicht einmal auf 0 Zeichen, aber der Typ ist kein Problem. – rici

+0

@rici Danke. Ich habe meinen Beitrag bearbeitet, befürchte aber, dass er anderen bereitgestellten Antworten ziemlich ähnlich ist. – erip

Verwandte Themen