2012-06-21 5 views
6

Ich versuche gerade ein etwas größeres Projekt mit dem Visual Studio 2012 Release Candidate, C++, zu kompilieren. Das Projekt wurde/wurde jetzt mit dem VS2010 kompiliert. . (Ich nur gierig bin die C++ 11 Dinge zu bekommen, also habe ich versucht :)Warum wurde die Bad_alloc (const char *) in Visual C++ 2012 privat gemacht?

Abgesehen von Dingen, die ich von mir erklären kann, verwendet das Projekt den Code wie folgt aus:

ostringstream ostr; 
ostr << "The " __FUNCTION__ "() failed to malloc(" << i << ")."; 
throw bad_alloc(ostr.str().c_str()); 

Die Compiler beschwert sich jetzt

error C2248: 'std::bad_alloc::bad_alloc' : cannot access private member declared 
    in class 'std::bad_alloc' 

... was wahr ist. Diese Version des Konstruktors ist jetzt privat.

Was war der Grund, diese Version des Konstruktors privat zu machen? Wird von C++ 11-Standard empfohlen, diesen Konstruktor nicht mit dem Argument zu verwenden?

(kann ich mir vorstellen, dass, wenn Zuweisung fehlgeschlagen ist, kann es zu Problemen führen, um zu versuchen, etwas Neues zu bauen. Es ist aber nur meine Vermutung.)

Danke, Petr

Antwort

14

Die C++ 11-Standard definiert bad_alloc als solche (18.6.2.1):

class bad_alloc : public exception { 
public: 
    bad_alloc() noexcept; 
    bad_alloc(const bad_alloc&) noexcept; 
    bad_alloc& operator=(const bad_alloc&) noexcept; 
    virtual const char* what() const noexcept; 
}; 

ohne Konstruktor, der eine Zeichenfolge erfolgt. Ein Anbieter, der einen solchen Konstruktor bereitstellt, würde den Code, der ihn verwendet, nicht portierbar machen, da andere Anbieter nicht verpflichtet sind, diesen bereitzustellen.

Der C++ 03-Standard definiert eine ähnliche Gruppe von Konstruktoren, weshalb VS diesem Teil des Standards nicht einmal vor C++ 11 folgte. MS versucht VS so standardkonform wie möglich zu machen, also haben sie wahrscheinlich gerade den Anlass (neuer VS, neuer Standard) genutzt, um eine Inkompatibilität zu beheben.

Edit: Nun habe ich VS2012 den Code zu sehen ist, ist es auch klar, warum die genannten Konstruktor privat bleibt, anstatt vollständig entfernt zu werden: Es scheint nur eine Verwendung dieser Konstruktor zu sein, in der bad_array_new_length Klasse . So wird bad_array_new_length in bad_alloc zu friend deklariert und kann daher diesen privaten Konstruktor verwenden. Diese Abhängigkeit hätte vermieden werden können, wenn bad_array_new_length nur die Nachricht in den Zeiger von what() gespeichert gespeichert, aber es ist sowieso nicht viel Code.

+0

Vielen Dank für die ausgearbeitete Antwort. – pepr

1

Wenn Sie daran gewöhnt sind, eine Nachricht zu übergeben, wenn Sie ein std :: bad_alloc werfen, ist es eine geeignete Methode, eine interne Klasse zu definieren, die von std :: bad_alloc abgeleitet ist und 'what' überschreibt, um die entsprechende Nachricht zu liefern.

Sie können die Klasse public machen und den Zuweisungskonstruktor direkt aufrufen oder eine Hilfsfunktion wie throw_bad_alloc ausführen, die die Parameter (und zusätzliche Skalarinformationen) übernimmt und in der internen Klasse speichert.

Die Nachricht wird nicht formatiert, bis "was" aufgerufen wird. Auf diese Weise kann das Abwickeln von Stapelspeicher etwas Speicher freigegeben haben, so dass die Nachricht mit dem tatsächlichen Grund (Speichererschöpfung, falsche Anforderungsgröße, Heap-Beschädigung usw.) an der Auffangstelle formatiert werden kann. Wenn die Formatierung fehlschlägt, weisen Sie einfach eine statische Nachricht zu und geben Sie sie zurück.

getrimmte Beispiel:

(Tipp:. Das Copy-Konstruktor kann nur _message zuweisen nullptr, anstatt die Nachricht zu kopieren, da die Nachricht auf Anfrage formatiert Den Umzug Konstruktor, natürlich kann es nur konfiszieren :-) .

class internal_bad_alloc: public std::bad_alloc 
    { 
    public: 
     // Default, copy and move constructors.... 

     // Assignment constructor... 
     explicit internal_bad_alloc(int errno, size_t size, etc...) noexcept: 
     std::bad_alloc() 
     { 
     // Assign data members... 
     } 

     virtual ~internal_bad_alloc(void) noexcept 
     { 
     // Free _Message data member (if allocated). 
     } 

     // Override to format and return the reason: 
     virtual const char* what(void) const noexcept 
     { 
     if (_Message == nullptr) 
      { 
      // Format and assign _Message. Assign the default if the 
      // format fails... 
      } 
     return _Message; 
     } 

    private: 
     // Additional scalar data (error code, size, etc.) pass into the 
     // constructor and used when the message is formatted by 'what'... 
     mutable char* _Message; 
     static char _Default[]; 
    } 
}; 

// 
// Throw helper(s)... 
// 
extern void throw_bad_alloc(int errno, size_t size, etc...) 
    { 
    throw internal_bad_alloc(errno, size, etc...); 
    }