2014-10-28 9 views
6

Ich bin dabei, einige Klassen für dynamische Arrays zu entwerfen (so etwas wie ein std :: vector). Der Grund, warum ich nicht std :: vector verwenden möchte, ist, dass meine C++ - Programme oft als eine Bibliothek verwendet werden, die von C/C++/Fortran/Delphi aufgerufen wird und daher Arrays als einen Zeiger aufnimmt. Aus Sicherheitsgründen kann ein std :: vector zur Konstruktionszeit keinen Zeiger stehlen. Mein Array1D kann als ein std :: vector arbeiten, kann aber auch mit einem Zeiger konstruiert werden. Leider scheint Visual Studio 2013 um mein Design besorgt zu sein. Bevor ich das Problem darlege, muss ich dieses Design erklären. HierDesign von dynamischen C++ - Arrays

ist das Layout meiner Klasse

template <typename T> 
class Array1D { 
private: 
    T* data_; 
    T* size_; // No stored as an int for optimisation purposes 
    bool owner_; 
public: 
    Array1D(int n) { 
     data_ = new T[n]; 
     size_ = data_ + n; 
     owner_ = true; 
    } 
    Array1D(T* data, int n) { 
     data_ = data; 
     size_ = data + n; 
     owner_ = false; 
    } 
    ... 
}; 

Die meiste Zeit, es funktioniert als std :: vector und owner_ auf true gesetzt ist. Man kann auch ein Array1D aus einem Zeiger konstruieren, und diesmal wird owner_ auf false gesetzt. In diesem Fall sind einige Operationen wie die Größenänderung nicht zulässig (durch eine Assert). Copykonstruktor und Zuordnung für das Array A sind als:

  • Array1D (const Array1D & B): Tief Kopie von B in A. Nach der Konstruktion, A besitzt seinen Speicher.
  • Array1D (Array1D & & B): Verschieben Sie den Vorgang in allen Fällen. Nach der Konstruktion ist der Eigentümerstatus von A derselbe wie B.
  • operator = (const Array1D & B): Tiefe Kopie von B in A. Wenn A seinen Speicher nicht besitzt, ist eine Bestätigung vorhanden, um zu überprüfen, dass A und B haben die gleiche Größe. Die Zuweisung ändert den Besitzstatus von A nicht.
  • operator = (Array1D & & B): Verschieben Sie den Vorgang, wenn A und B ihren Speicher besitzen. Andernfalls machen wir eine tiefe Kopie, und die Größe wird mit einem Assert überprüft, wenn A seinen Speicher nicht besitzt. Die Zuordnung nicht die Eigentümerstatus ändern A.

I die gleiche Idee meiner 2-dimensionale Array, dessen Elemente in Zeilenhauptordnung

template <typename T> 
class Array2D { 
private: 
    T* data_; 
    T* size_[2]; 
    bool owner_; 
public: 
    Array2D(int n, int p) { 
     data_ = new T[n]; 
     size_[0] = data_ + n; 
     size_[1] = data_ + p; 
     owner_ = true; 
    } 
    Array1D(T* data, int n, int p) { 
     data_ = data; 
     size_[0] = data + n; 
     size_[1] = data + p; 
     owner_ = false; 
    } 
    ... 
    Array1D<T> operator()(int i) { 
     Array1D<T> row(data_ + i * nb_columns(), nb_columns()); 
     return row; 
    } 
    ... 
    int nb_columns() const { 
     return static_cast<int>(size_[1] - data_); 
    } 
}; 

Die Array1D zurückgegeben durch Bediener gespeichert werden angewendet wurden () (int i) besitzt keinen Speicher und enthält einen Zeiger auf die i-te Zeile des Array2D-Objekts. Ist nützlich in der folgenden Art von Code

sort(Array1D<T>& A); // A function that sorts array in place 

Array2D<double> matrix(5, 100); // Construct an array of 5 rows and 100 columns 
...        // Fill the array 
sort(matrix(3))     // Sort the 4th row 

Diese „temporäre Ansichten“ für die Zeilen eines 2-dimensionalen Arrays sind sehr nützlich, aber ich ziehe sie auf temporäre Objekte zu begrenzen Aliasing zu begrenzen.

Leider bekomme ich mit Visual Studio 2013 die folgende Warnung von der IDE für die Zeilensortierung (matrix (3)): "Optionen zum Binden von r-Wert an l-Wert-Referenz ist nicht standardmäßige Microsoft C++ Erweiterung" . Ich verstehe, dass Matrix (3) ein Objekt ist, das temporär lebt und es durch eine Art verändert, die merkwürdig aussieht. Da es sich jedoch um eine "Ansicht" handelt, wird durch Modifizieren des Speichers der Speicher der Matrix modifiziert und ist nützlich.

Also folgendes meine Fragen sind:

  • Ist das, was ich gültige C++ tue? (Ändern eines temporären Werts)
  • Gibt es einen Fehler in diesem Design?

PS: Der vollständige Code ist unter Github verfügbar.

+0

Der Prototyp von 'sort', den Sie angegeben haben, benötigt einen Werttyp, keinen Lvalue-Referenztyp. – ecatmur

+0

Wie ist Ihr 'Array1D operator() (int i);' implementiert? – Ashalynd

+0

@ecatmut: Danke für Ihre Kommentare. Der Beitrag wurde bearbeitet. – InsideLoop

Antwort

0

Ist was ich tue gültig C++? (Ändern eines temporären Werts)

Es ist nicht. Nicht konstante lvalue Referenzen können nicht auf temporäre Objekte binden: http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/

Gibt es einen Fehler in diesem Entwurf?

Sie ändern den Inhalt, der in einem Objekt eingeschlossen ist. Da Sie einen L-Wert haben müssen, wäre es einfach, indem er eine Zwischengröße festgelegt werden:

auto m_temp_lvalue = matrix(3); // get the 4th row 
sort(m_temp_lvalue); // sort the 4th row 

Ich hoffe, es hilft.

+0

Danke für Ihre Erklärung. Obwohl Ihre Idee der intermediären Variablen funktioniert, habe ich mich schließlich dazu entschieden, diese "Ansichten" zu vermeiden und nur ein Array1D auf einen Speicherort im Speicher zu zeigen. Es macht die Dinge sicherer. – InsideLoop

Verwandte Themen