2010-08-30 17 views
7

que tienen debajo de pieza de código¿Es necesario sobrecargar el nuevo operador de colocación, cuando sobrecargamos un nuevo operador?

class Test 
{ 
public: 
    Test(){} 
    Test(int i) {} 

    void* operator new (size_t size) 
    { 
     void *p = malloc(size); 
     return p; 
    } 
    //void* operator new (size_t size, Test *p) 
    //{ 
    // return p; 
    //} 
}; 

int main() { 
    Test *p = new Test; 
    int i = 10; 
    new(p) Test(i); 
} 

Por encima de pieza de código no se compila en Visual Studio, a menos que elimine el comentario de la función nuevo operador la colocación sobrecargado. Si hago un comentario normal sobrecargado nuevo, en ese caso también funciona bien. Es una sobrecarga de colocación nueva obligatoria cuando se sobrecarga el operador nuevo normal (Si la colocación nueva debe usarse para esa clase)

El código relacionado con la eliminación de ubicaciones no se muestra aquí.

Respuesta

3

Normalmente no, ya que no se usa a menudo. Pero podría ser necesario, ya que cuando sobrecarga operator new en una clase, oculta todas las sobrecargas del ::operator new global.

Por lo tanto, si desea utilizar la ubicación nueva en objetos de esa clase, haga; de lo contrario, no. Lo mismo ocurre con nothrow nuevo.

Si acabas de cambiar el esquema de asignación, y te sorprende que alguien esté utilizando la ubicación nueva a tus espaldas, eso podría ser algo para investigar antes de aplicar esta curita.

Si la clase se utiliza dentro de contenedores de biblioteca estándar, no directamente con new, el esquema de asignación personalizada debe definirse mediante una clase de asignador, no una sobrecarga. El asignador predeterminado std::allocator no respeta las sobrecargas del miembro operator new, pero las omite. Vea abajo.


Negación: Clase-alcance operator new sobrecargas son útiles principalmente para la depuración, e incluso entonces es difícil de conseguir de forma fiable la semántica significativas. Cuidado:

  • Es necesario también sobrecargue operator delete. (No se hace en el ejemplo en esta pregunta.)

  • Las sobrecargas se sostendrán por la sintaxis calificada ::new T. Usted no puede evitar tal desvío. Esta es la forma en que std::allocator<T> asigna cosas. Puedes especializarte en std::allocator para tus tipos, pero eso ya está dentro de la madriguera.

  • Para cada ::operator new sobrecarga introducida por cualquier biblioteca, incluyendo la colocación canónica nueva de <new>, tendrá que considerar si se aplica a su clase y decidir si desea añadir una sobrecarga, o de otra forma lidiar con el fracaso de no calificado new expresiones.

  • Para cada ::operator new que adopte en su clase, debe proporcionar la ubicación de miembro correspondiente operator delete con la semántica correcta. Esto se llama en caso de que el constructor salga por excepción. Si no se tiene, se produciría una pérdida de memoria solo en circunstancias muy específicas, en un grupo de recursos posiblemente restringido.

En resumen, miembro de operator new es la antítesis de codificación defensiva.

+0

En realidad es una buena idea implementar placement y nothrow 'new' cada vez que implemente' nuevo' personalizado por esta misma razón. Podría romper el código existente al no proporcionar las seis versiones de nuevo y eliminar (no olvide formularios de matriz). –

+0

la colocación 'new' no se usa a menudo en el código, pero los contenedores STL frecuentemente lo usan para separar su asignación de memoria de la construcción de objetos. –

+0

@Philip: Esa es una bandera roja, dado que 'std :: allocator' obtiene su memoria de' :: operator new'. En ese caso, la solución es implementar un asignador personalizado, no para habilitar el estándar. – Potatoswatter

1

El nuevo operador de ubicación no existe de forma predeterminada para una clase, por lo que cuando realiza una llamada a new(p) Test(i);, el compilador de C++ no puede encontrar una definición de la función comentada en el ejemplo anterior. Si quita el comentario del operador de ubicación nuevo para su clase y comenta el "normal", se usará el nuevo operador predeterminado "normal" y se compilará su código.

0

implementaciones de std :: _ Construir utilizar el global colocación nueva. Entonces las preocupaciones sobre la compatibilidad STL no deberían ser preocupaciones. Pero la preocupación por romper el código existente, que puede haber sido escrita

new ((void*)p) thing;

en lugar de

::new ((void*)p) thing;

es sin duda un punto válido.

Cuestiones relacionadas