2010-04-28 15 views
6

Manchmal ist es sinnvoll, die Startadresse einer std::vector zu verwenden und diese Adresse vorübergehend als Adresse eines regelmäßig zugewiesenen Puffers zu behandeln.
Zum Beispiel ersetzen diese:C++: die Adresse des Anfangs eines std :: vector erhalten?

char* buf = new char[size]; 
fillTheBuffer(buf, size); 
useTheBuffer(buf, size); 
delete[] buf; 

mit diesem:

vector<char> buf(size); 
fillTheBuffer(&buf[0], size); 
useTheBuffer(&buf[0], size); 

Dies hat den Vorteil ist natürlich, dass der Puffer automatisch freigegeben wird, und ich muss die delete[] nicht darum kümmern.

Das Problem, das ich damit habe, ist, wenn Größe == 0. In diesem Fall funktioniert die erste Version in Ordnung. Ein leerer Puffer ist "allokiert" und die nachfolgenden Funktionen haben keine Größe, sie erhalten die Größe == 0.
Die zweite Version schlägt jedoch fehl, wenn size == 0, da der Aufruf buf[0] zu Recht eine Behauptung enthalten kann, die 0 < size.

Gibt es eine Alternative zu dem Idiom &buf[0], die die Adresse des Beginns des Vektors zurückgibt, selbst wenn der Vektor leer ist?

Ich habe auch über die Verwendung buf.begin() in Betracht gezogen, aber nach dem Standard ist es nicht einmal garantiert, einen Zeiger zurückzugeben.

+0

Das sieht wie ein Versehen in der STL-Bibliothek aus. C++ erlaubt es Ihnen, 'new T [0]' zuzuordnen und gibt einen gültigen Zeiger für Situationen wie diesen zurück, aber die meisten Implementierungen der STL-Assertion, nur für den Fall, dass Sie diesem Element oder etwas zuweisen. – AshleysBrain

+0

Wie würde es den Unterschied zwischen '& buf [0]' und 'buf [0] = 1 'wissen? – shoosh

Antwort

8

Ich denke, Sie müssten nur überprüfen.

Vielleicht eine Nutzenfunktion:

template <class T, class Alloc> 
T* data(std::vector<T, Alloc>& vec) 
{ 
    return vec.empty() ? 0 : &vec[0]; 
} 

template <class T, class Alloc> 
const T* data(const std::vector<T, Alloc>& vec) 
{ 
    return vec.empty() ? 0 : &vec[0]; 
} 
+1

1. Bemerkung: lohnt es sich, auf 'boost :: addressof' zu investieren, wenn' T' einen überladenen '&' operator hat? Zweite Bemerkung: Ein zweiter Template-Parameter 'Alloc' würde die Funktion etwas universeller machen. –

+1

@Matthieu: In Bezug auf die erste Bemerkung: http://stackoverflow.com/questions/2719832/why-is-overloading-operator-prohibited-for-classes-stored-in-stl-containers. Sie können keinen Typ speichern, für den '& t' seine Adresse nicht zurückgibt. - Zweite Bemerkung zur Antwort hinzugefügt. – UncleBens

1

Es gibt keine Funktion für das, obwohl std::basic_stringdata() hat, die genau das tut, was Sie brauchen.

Sie werden so etwas wie buf.size()?&buf[0]:0;

1

denken verwenden, habe ich Sie in jedem Fall sicher sein sollte. Ich glaube, dass die Unterschiede zwischen vector :: operator [int] und vector :: at (int) darin bestehen, dass die Operatorüberladung [] nicht die Überprüfung der Grenzen durchführt. Die Verwendung von buf [0] sollte frei von Behauptungen sein!

+0

Leider irren Sie sich. MSVC2008's Vektor hat Assertions auf 'operator []'. – shoosh

+0

Danke für die Aufklärung! – acanaday

+4

Als Folge habe ich gelernt, dass das folgende '#define _SECURE_SCL 0' dieses Verhalten deaktiviert. – acanaday

1

Wenn Sie fillTheBuffer ändern und theTheBuffer verwenden können, um ein Paar Iteratoren zu verwenden, lösen Sie das Problem genauso wie die Standardbibliothek es löste.