¿Cómo evitar que un objeto se cree en el montón?

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

Foo *ptr = new Foo; 

y solo les permiten hacer esto:

 Foo myfooObject; 

¿Alguien tiene alguna idea?

Aclamaciones,

La respuesta de Nick es un buen punto de partida, pero incompleto, ya que realmente necesitas 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 

(Una buena práctica de encoding sugiere que también deberías sobrecargar los operadores de eliminar y eliminar []; lo haría, pero dado que no se van a llamar, no es realmente necesario).

Pauldoo también tiene razón en que esto no sobrevive agregando en Foo, aunque sí sobrevive heredando de Foo. Podrías hacer un poco de magia de meta-progtwigció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.

Podría sobrecargar a Foo y hacerlo privado. Esto significaría que el comstackdor 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); }; 

PD. 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! 😉

No sé cómo hacerlo de manera confiable y portátil … pero …

Si el objeto está en la stack, entonces usted puede ser capaz de afirmar dentro del constructor que el valor de ‘this’ siempre está cerca del puntero de la stack. Hay una buena posibilidad de que el objeto esté en la stack si este es el caso.

Creo que no todas las plataformas implementan sus stacks en la misma dirección, por lo que es posible que desee hacer una prueba única cuando la aplicación comience a verificar la forma en que crece la stack. O bien, haga un poco de fudge:

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

@Mella

Esto podría evitarse creando una clase que derive de o agregue Foo. Creo que lo que sugiero (aunque no es robusto) aún funcionaría para las clases derivadas y agregadas.

P.ej:

 struct MyStruct { Foo m_foo; }; MyStruct* p = new MyStruct(); 

Aquí he creado una instancia de ‘Foo’ en el montón, evitando el nuevo operador oculto de Foo.

Debido a que los encabezados de depuración pueden anular la nueva firma del operador, es mejor usar las … firmas como un remedio completo:

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

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

esto se puede evitar haciendo que los constructores sean privados y proporcionando un miembro estático para crear un objeto en la stack

 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 stack.

Podría declarar una función llamada “operador nuevo” dentro de la clase Foo que bloquearía el acceso a la forma normal de nueva.

¿Es este el tipo de comportamiento que quieres?

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