c++ - diferencia - ¿Cómo evitar que un objeto se cree en el montón?
heap vs stack diferencia (8)
¿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,
@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.
No estoy seguro si esto ofrece oportunidades de tiempo de compilación, pero ¿ha mirado sobrecargar el "nuevo" operador para su clase?
No sé cómo hacerlo de manera confiable y portátil ... pero ...
Si el objeto está en la pila, entonces usted puede ser capaz de afirmar dentro del constructor que el valor de ''this'' 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 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 pila. O bien, haga un poco de fudge:
FooClass::FooClass() {
char dummy;
ptrdiff_t displacement = &dummy - reinterpret_cast<char*>(this);
if (displacement > 10000 || displacement < -10000) {
throw "Not on the stack - maybe..";
}
}
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?
Podría sobrecargar a 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);
};
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! ;-)
Puede declararlo como una interfaz y controlar la clase de implementación más directamente desde su propio código.
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;
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 codificación 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-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.