2015-02-03 5 views
6

Ich möchte in der Lage sein, einen benutzerdefinierten Zuordner mit Std :: Vector zu verwenden, so dass kleine Datenpuffer (sagen wir, weniger als 1024 Bytes) werden auf dem Stapel gespeichert, und nur längere Vektoren werden auf dem Heap gespeichert. Als jemand, der einen Hintergrund in Fortran hat, verursacht es mir jedes Mal körperliche Schmerzen, wenn ich eine Stapelspeicherzuweisung machen muss, um ein halbes Dutzend Elemente für die Dauer einer fünfzeiligen Subroutine zu speichern!Howard Hinnants short_alloc (C++ 11-Version) zum Kompilieren in Visual C++ 2015

Howard Hinnant hat seinen short_alloc Allokator veröffentlicht, der genau das tut, nach dem ich suche, und wenn ich es mit gcc kompiliere, funktioniert es ein Vergnügen. In Visual C++ kann ich es jedoch nicht kompilieren. In Visual C++ 2013 bestand der Teil des Problems darin, dass zu viele C++ 11 Schlüsselwörter nicht unterstützt wurden, aber ich stieß immer noch auf ein Problem, selbst wenn ich alle diese DEFINE's entfernt hatte. Heute habe ich versucht, in Visual C++ 2015 CTP 5 zu kompilieren, und die Schlüsselwörter werden jetzt alle unterstützt, aber die Kompilierung schlägt aus dem gleichen Grund fehl.

Das Problem ist folgendes: ein Grund, warum ich nicht ganz verstehen kann behaupten zu, die Copykonstruktor Code Standardeinstellungen des Hinnant aber löscht die Kopie Zuweisungsoperator:

short_alloc(const short_alloc&) = default; 
short_alloc& operator=(const short_alloc&) = delete; 

Wenn zu kompilieren versuchen, dies löst die folgende Fehler in Visual C++:

xmemory0(892): error C2280: 'short_alloc<int,1024> &short_alloc<1024>::operator =(const short_alloc<1024> &)': attempting to reference a deleted function 

Was mich verwirrt noch mehr ist, dass wenn ich Hinnant den Code ändern sagen

short_alloc(const short_alloc&) = default; 
short_alloc& operator=(const short_alloc&) = default; 

... dann erhalte ich immer noch genau die gleiche Fehlermeldung.

Als Referenz hier ist mein Testcode:

#include <iostream> 
#include <vector> 
#include "short_alloc.h" 

void populate_the_vector(std::vector<int, short_alloc<int, 1024> > &theVector) 
{ 
    arena<1024> B; 
    std::vector<int, short_alloc<int, 1024> > anothertestvec{(short_alloc<int, 1024>(B))}; 
    anothertestvec.resize(10); 
    for (int i=0; i<10; ++i) 
    { 
     anothertestvec[i] = i; 
    }  
    theVector = std::move(anothertestvec); // Actually causes a copy, as the Arenas are different 
} 

int main() 
{ 
    arena<1024> A; 
    std::vector<int, short_alloc<int, 1024> > testvec{(short_alloc<int, 1024>(A))}; 
    populate_the_vector(testvec); 
    printf("Testvec(10)=%d\r\n", testvec[5]); 
    return 0; 
} 

Der Kompilierungsfehler geht weg, wenn ich

theVector = std::move(anothertestvec); 

so offensichtlich das zugrunde liegende Problem besteht darin, dass Visual C++ Ansätze sagen die Linie Kommentar-out die Kopie auf andere Weise als gcc. Trotzdem weiß ich nicht, wie ich von hier aus vorgehen soll. Gibt es eine Möglichkeit, das in Visual C++ zu funktionieren?

+0

Das Zuweisungsoperator ist wahrscheinlich nicht verfügbar für die Basisklasse zur Verfügung steht edit: oder für ein Mitglied), und daher führt das Generieren der Standardimplementierung auch zu einem Löschen. – Mehrdad

+0

@Mehrdad Es gibt keine Basisklasse, aber ein Referenzelement. –

+0

@ T.C .: Oder, ja. Ich habe nicht wirklich darüber nachgedacht, welcher es sein könnte. – Mehrdad

Antwort

9

Der einfachste Hack, dass ich denken kann ersetzt

short_alloc& operator=(const short_alloc&) = delete; 

mit

short_alloc& operator=(const short_alloc&) 
{ 
    assert(false && "this should never be called"); 
    return *this; 
}; 

Es sieht aus wie ein ziemlich gefährlich Hack, aber es ist eigentlich gar nicht so schlecht in diesem speziellen Fall, und hier ist Warum:

Der Grund, dass die ursprüngliche Version nicht in VC++ kompiliert, ist, dass seine Standardbibliothek Implementierung von std::vector 's Verschieben Zuweisungsoperator ist macht den klassischen Fehler, std::allocator_traits<...>::propagate_on_container_move_assignment::value mit einer if() Anweisung zu testen.

Es macht den ordnungsgemäßen Prüfung und weisen nicht die allocator wenn das Merkmal Wert false ist (und bewegt die Elemente einzeln auf der anderen Seite, wenn die Zuweiser verschieden sind, wie von der Norm gefordert), aber der Code auf der if() Zweig muss noch kompilieren, obwohl es für diese Art von Zuordner nie erreicht werden wird.

Daher wird dieser Zuweisungsoperator niemals zur Laufzeit von der Container-Implementierung aufgerufen, und deshalb ist der Hack in diesem speziellen Fall sicher.

(Die lustigste Sache ist, dass eine Zeile unterhalb diesen if() wird die tatsächlichen Bewegungs richtig mit einer Hilfsfunktion mit Tag-Versand implementiert ...)


Dies basiert auf der Standard-Bibliothek-Implementierung, kommt mit Visual C++ 2013 Update 4.

Update: Wie vom OP in den Kommentaren gemeldet, hat VC14 CTP5 das gleiche Problem.


Update 2: Wie in den Kommentaren für die bug report angegeben, wird die Fehlerbehebung für dieses Problem in der endgültigen Version von Visual C (++ 2015

+0

Danke, das funktioniert in VC14 CTP 5 und gibt das gewünschte Verhalten. –

+0

@EosPengwern Können Sie die Quellen für das CTP noch einmal überprüfen, wenn das 'if()' noch da ist, nur um sicher zu gehen? Außerdem sollte dieser Fehler gemeldet werden. Willst du es selbst machen? – bogdan

+0

Ich kann überhaupt keinen Unterschied zwischen den relevanten Teilen des VC \ include \ -Vektors in VC12 und VC14 sehen, so dass es aussieht, als wäre derselbe Fehler vorhanden. Ich habe ein MSDN-Support-Abonnement, sodass ich es selbst melden kann. Nochmals vielen Dank für Ihre Hilfe. –