2012-06-21 12 views
6

Sto solo cercando di compilare un progetto un po 'più grande usando la versione candidata di Visual Studio 2012, C++. Il progetto è stato/è compilato utilizzando VS2010 ora. . (Io sono solo avidi di ottenere i C++ 11 cose, così ho provato :)Perché il bad_alloc (const char *) è stato reso privato in Visual C++ 2012?

parte delle cose che posso spiegare da solo, il progetto utilizza il codice come questo:

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

Il il compilatore si lamenta ora

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

... che è vero. Quella versione di constructor è ora privata.

Qual è stato il motivo per rendere privata questa versione del costruttore? È raccomandato dallo standard C++ 11 di non usare quel costruttore con l'argomento?

(Posso immaginare che, se l'assegnazione non è riuscita, potrebbe causare più problemi per cercare di costruire qualcosa di nuovo. Tuttavia, è solo la mia ipotesi.)

Grazie, Petr

risposta

14

Il C++ 11 definisce standard bad_alloc quanto tali (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; 
}; 

senza costruttore che richiede una stringa. Un fornitore che fornisce tale costruttore renderebbe il codice non utilizzabile, poiché altri fornitori non sono obbligati a fornirlo.

Lo standard C++ 03 definisce un insieme simile di costruttori, quindi VS non ha seguito questa parte dello standard prima del C++ 11. MS cerca di rendere VS il più conforme possibile, quindi probabilmente hanno appena usato l'occasione (nuovo VS, nuovo standard) per correggere un'incompatibilità.

Edit: Ora che ho visto il codice di VS2012, è anche chiaro perché il costruttore citato è lasciato privata, invece di essere completamente rimosso: sembra che ci sia un solo uso di quel costruttore, nella classe bad_array_new_length . Quindi bad_array_new_length è dichiarato come in bad_alloc e può quindi utilizzare quel costruttore privato. Questa dipendenza avrebbe potuto essere evitata se bad_array_new_length memorizzasse il messaggio nel puntatore utilizzato da what(), ma non è comunque molto codice.

+0

Grazie mille per la risposta elaborata. – pepr

1

Se si è abituati a passare un messaggio quando si lancia uno std :: bad_alloc, una tecnica adatta è definire una classe interna derivata da std :: bad_alloc e sovrascrivere 'what' per fornire il messaggio appropriato.

È possibile rendere pubblica la classe e chiamare direttamente il costruttore del compito oppure eseguire una funzione di supporto, ad esempio throw_bad_alloc, che accetta i parametri (e ulteriori informazioni scalari) e li memorizza nella classe interna.

Il messaggio non è formattato fino a quando 'cosa' viene chiamato. In questo modo, lo sbobinamento dello stack potrebbe aver liberato un po 'di memoria in modo che il messaggio possa essere formattato con il motivo reale (esaurimento della memoria, dimensioni richieste errate, danneggiamento dell'heap, ecc.) Nel sito di cattura. Se la formattazione fallisce, è sufficiente assegnare e restituire un messaggio statico.

esempio rasato:

(Suggerimento:. Il costruttore di copia può semplicemente assegnare _message a nullptr, piuttosto che copiare il messaggio in quanto il messaggio è formattato su richiesta Il costruttore mossa, ovviamente può solo confiscare esso :-) .

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...); 
    }