2012-06-21 14 views
6

Estoy tratando de compilar un proyecto un poco más grande usando el Candidato de lanzamiento de Visual Studio 2012, C++. El proyecto fue/está compilado utilizando el VS2010 ahora. . (Soy sólo codicioso para obtener los C++ 11 cosas, así que he intentado :)¿Por qué bad_alloc (const char *) se hizo privado en Visual C++ 2012?

Aparte de las cosas que puedo explicar por mí mismo, el proyecto utiliza el código de la siguiente manera:

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

El el compilador ahora se queja

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

... que es verdad. Esa versión de constructor ahora es privada.

¿Cuál fue el motivo para hacer que esa versión del constructor sea privada? ¿El estándar C++ 11 recomienda no usar ese constructor con el argumento?

(Me puedo imaginar que si la asignación no, puede causar más problemas al tratar de construir algo nuevo. Sin embargo, es sólo mi suposición.)

Gracias, Petr

Respuesta

14

El C++ 11 define estándar bad_alloc como tales (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; 
}; 

Con ningún constructor que toma una cadena. Un proveedor que proporcione dicho constructor haría que el código que lo utiliza no sea portátil, ya que otros proveedores no están obligados a proporcionarlo.

El estándar C++ 03 define un conjunto similar de constructores, por lo que VS no siguió esta parte del estándar incluso antes de C++ 11. MS intenta hacer que VS sea lo más compatible posible, por lo que probablemente haya utilizado la ocasión (nuevo VS, nuevo estándar) para corregir una incompatibilidad.

Editar: Ahora que he visto el código de VS2012, también es claro por qué el constructor mencionado se deja privada, en lugar de ser eliminado por completo: no parece ser sólo un uso de ese constructor, en la clase bad_array_new_length . Entonces bad_array_new_length se declara friend en bad_alloc, y por lo tanto puede usar ese constructor privado. Esta dependencia se podría haber evitado si bad_array_new_length acaba de almacenar el mensaje en el puntero utilizado por what(), pero de todos modos no es una gran cantidad de código.

+0

Muchas gracias por la respuesta elaborada. – pepr

1

Si está acostumbrado a pasar un mensaje cuando tira un std :: bad_alloc, una técnica adecuada es definir una clase interna que se deriva de std :: bad_alloc, y anular "qué" proporcionar el mensaje apropiado.

Puede hacer que la clase sea pública y llamar al constructor de asignaciones directamente, o realizar una función auxiliar, como throw_bad_alloc, que toma los parámetros (e información escalar adicional) y los almacena en la clase interna.

El mensaje no se formatea hasta que se llame 'qué'. De esta forma, el desenrollado de la pila puede haber liberado parte de la memoria para que el mensaje pueda ser formateado con la razón real (agotamiento de la memoria, tamaño de solicitud incorrecta, corrupción del montón, etc.) en el sitio de captura. Si el formateo falla, simplemente asigne y devuelva un mensaje estático.

ejemplo guarnecidos

(Consejo:. El constructor de copia solo puede asignar a _Message NullPtr, en lugar de copiar el mensaje ya que el mensaje se formatea en la demanda El movimiento constructor, por supuesto, sólo puede confiscar :-) .

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