2016-07-01 24 views
1

Dies ist ein konstruiertes Beispiel, aber die folgenden Punkte beachten:Warum sollten wir Zeigerarithmetik nicht mit gsl :: not_null verwenden?

#include <iostream> 
#include "gsl.h" 

int main(){ 

    //object or array that I'd like to iterate over one byte at a time 
    char array[] = {'a','b','c','d','e','f'}; 

    //create a C-like iterator 
    char* it = &array[0]; 

    //use pointer arithmetic to process 
    std::cout << *it << std::endl; it++; 
    std::cout << *it << std::endl; it++; 
    std::cout << *it << std::endl; it++; 
} 

Zur Sicherheit würde ich den Zeiger mit not_null markieren möchte.
Dies kompiliert jedoch nicht.

#include "gsl.h" 
#include <iostream> 

int main(){ 

    //object or array that I'd like to iterate over one byte at a time 
    char array[] = {'a','b','c','d','e','f'}; 

    //create a C-like iterator 
    gsl::not_null<char*> it = &array[0]; 

    //use pointer arithmetic to process 
    std::cout << *it << std::endl; it++; 
    std::cout << *it << std::endl; it++; 
    std::cout << *it << std::endl; it++; 
} 

Eine Ausnahme von not_null ‚s Klasse:

// unwanted operators...pointers only point to single objects! 
// TODO ensure all arithmetic ops on this type are unavailable 
not_null<T>& operator++() = delete; 
not_null<T>& operator--() = delete; 
not_null<T> operator++(int) = delete; 
not_null<T> operator--(int) = delete; 
not_null<T>& operator+(size_t) = delete; 
not_null<T>& operator+=(size_t) = delete; 
not_null<T>& operator-(size_t) = delete; 
not_null<T>& operator-=(size_t) = delete; 

Ich bin verwirrt, warum sie dies getan haben.
Warum kann ich keinen Zeiger haben, der seinen Wert ändert?

Vor allem, wenn es einfach ist, zu umgehen:

it = &array[0]; 
it = static_cast<char*>(it)+1; 

Fehle ich den Punkt der not_null?
Die C++ Guidelines decken nicht, warum so etwas ein schlechter Anwendungsfall wäre.

+0

Vermutlich ist 'not_null' für einzelne Objekte gedacht, die unter keinen Umständen null sein können. Es ist möglich, die Zeit zu kompilieren, um zu überprüfen, dass sie anfangs nicht Null sind, aber wenn Zeigerarithmetik erlaubt war, konnten Sie nicht garantieren, dass sie nie null sein würden. Sie verbieten also Zeigerarithmetik und führen dabei eine neue Garantie ein, dass der Zeiger nur neu zugewiesen werden kann; Die Besetzung betrügt hier (Wiedereinführung der Möglichkeit von Null), aber so sei es. – ShadowRanger

+0

Sie sollten keine C-Idiome in C++ verwenden, ich sage es einfach. Bleiben Sie bei einfachen char * -Arrays/Zeigern, wenn Sie sie mit '++' –

+0

@self bearbeiten wollen: Ich würde das Iterator-Protokoll in C++ als Formalisierung und Verallgemeinerung der Zeigerarithmetik ansehen, es ist nicht besonders C-spezifisch. – ShadowRanger

Antwort

4

Dies ist nicht zulässig, da ein Zeiger kein Array ist. Ja, ein Array kann Zerfall in einen Zeiger, aber wie das Wort suggeriert, verliert solcher Zerfall Informationen. Der resultierende Zeiger ist nicht äquivalent zu dem Array.

Im Gegensatz dazu verliert die Umwandlung eines Arrays in eine gsl::span keine Informationen. Die Größe des Arrays wird beibehalten, ebenso wie die Fähigkeit, es zu durchlaufen.

not_null ist für einen Zeiger auf ein Objekt, nicht ein Array von Objekten. Genauso wie unique_ptr und shared_ptr keine Zeigerarithmetik zulassen. Wenn Sie die Zeigerarithmetik verwenden möchten, um ein Array zu verarbeiten, lautet die richtige Antwort gsl::span und seine Iteratoren.