2008-08-14 13 views
22

¿Alguien sabe cómo puedo, en código de C++ independiente de la plataforma evitar que un objeto se cree en el montón? Es decir, para una clase de "Foo", quiero evitar que los usuarios hacer esto:¿Cómo evitar que un objeto se cree en el montón?

Foo *ptr = new Foo; 

y sólo les permiten hacer esto:

Foo myfooObject; 

¿Alguien tiene alguna idea?

Saludos,

+2

¿Por qué querrías hacer esto? –

+0

Lo contrario, que también puede ser interesante para los lectores: http://stackoverflow.com/questions/124880/is-it-possible-to-prevent-stack-allocation-of-an-object-and-only-allow- it-to-be – kevinarpe

Respuesta

24

Nick's answer es un buen punto de partida, pero incompleto, ya que en realidad necesita sobrecargar:

private: 
    void* operator new(size_t);   // standard new 
    void* operator new(size_t, void*); // placement new 
    void* operator new[](size_t);  // array new 
    void* operator new[](size_t, void*); // placement array new 

(Buenas prácticas de codificación sugeriría también se debe sobrecargar el borrado y eliminar los operadores [] - Me gustaría, pero ya que no van a ser llamado no es realmente necesario.)

Pauldoo también es cierto que este no sobrevive en la agregación de Foo, aunque sobrevive heredando de Foo. Podrías hacer un poco de magia de meta-programación de plantillas para AYUDAR a prevenir esto, pero no sería inmune a los "usuarios malvados" y probablemente no valga la pena la complicación. La documentación de cómo se debe usar y la revisión del código para garantizar que se usa correctamente son las únicas ~ 100% de la ruta.

+1

¿Un constructor privado combinado con un método público de fábrica estático (retorno por valor) logrará lo mismo? – kevinarpe

+1

@kevinarpe Depende de cuán literalmente estemos leyendo la pregunta. El código exacto 'Foo myfooObject;' de la pregunta no se compilará si lo hiciste. Dicho esto, prefiero un enfoque más parecido a lo que estás sugiriendo, si estoy tratando de controlar cómo se crean los objetos. –

-1

Se puede declarar una función llamada "nueva operador" dentro de la clase Foo que bloquearía el acceso a la forma normal de nuevo.

¿Es este el tipo de comportamiento que desea?

7

Podría sobrecargar el nuevo Foo y hacerlo privado. Esto significaría que el compilador se lamentaría ... a menos que esté creando una instancia de Foo en el montón desde dentro de Foo. Para captar este caso, simplemente no podría escribir el nuevo método de Foo y luego el enlazador se quejaría acerca de los símbolos indefinidos.

class Foo { 
private: 
    void* operator new(size_t size); 
}; 

PS. Sí, sé que esto se puede eludir fácilmente. Realmente no lo estoy recomendando, creo que es una mala idea, ¡solo estaba respondiendo la pregunta! ;-)

-1

No estoy seguro si esto ofrece oportunidades de tiempo de compilación, pero ¿ha mirado sobrecargar el 'nuevo' operador para su clase?

6

no sé cómo hacerlo de forma fiable y de una manera portátil .. pero ..

Si el objeto está en la pila entonces usted podría ser capaz de hacer valer dentro del constructor que el valor de ' esto 'siempre está cerca del puntero de la pila. Hay una buena posibilidad de que el objeto esté en la pila si este es el caso.

Creo que no todas las plataformas implementan sus pilas en la misma dirección, por lo que es posible que desee hacer una prueba de una sola vez cuando se inicia la aplicación para verificar de qué manera la pila crece .. o hacer algo de dulce de azúcar:

FooClass::FooClass() { 
    char dummy; 
    ptrdiff_t displacement = &dummy - reinterpret_cast<char*>(this); 
    if (displacement > 10000 || displacement < -10000) { 
     throw "Not on the stack - maybe.."; 
    } 
} 
+0

¡Un enfoque interesante! – hackworks

+0

Creo que este y el maniquí siempre estarán cerca uno del otro, sin importar si están en el montón o en la pila – Vargas

+1

@Vargas - No estoy de acuerdo. 'ficticio' siempre estará en la pila, porque es una variable local automática. El puntero 'this' puede apuntar a la pila (si FooClass se usa como una variable local) o al montón (si FooClass se asigna en el montón, o se agrega dentro de una clase que luego se asigna en el montón). – pauldoo

3

@ Nick

Esto podría eludirse mediante la creación de una clase que se deriva de los agregados o Foo. Creo que lo que sugiero (aunque no es robusto) aún funcionaría para las clases derivadas y agregadas.

por ejemplo:

struct MyStruct { 
    Foo m_foo; 
}; 

MyStruct* p = new MyStruct(); 

Aquí he creado una instancia de 'Foo' en el montón, sin pasar por nuevo operador oculto de Foo.

+0

+1 ¡Bonito truco! La conversión de tipos también puede ayudar – Viet

0

Puede declararlo como una interfaz y controlar la clase de implementación más directamente desde su propio código.

0

Debido a las cabeceras de depuración pueden anular el operador nueva firma, lo mejor es utilizar las firmas ... como un remedio completo:

private: 
void* operator new(size_t, ...) = delete; 
void* operator new[](size_t, ...) = delete; 
0

esto se puede evitar haciendo que los constructores privados y proporcionar un elemento estático para crear un objeto en la pila

Class Foo 
{ 
    private: 
     Foo(); 
     Foo(Foo&); 
    public: 
     static Foo GenerateInstance() { 
      Foo a ; return a; 
     } 
} 

Esto hará que la creación del objeto siempre esté en la pila.

Cuestiones relacionadas