¿Por qué debería / no debería usar el operador “new” para crear instancias de una clase, y por qué?

StackOverflow https://stackoverflow.com/questions/572255

  •  05-09-2019
  •  | 
  •  

Pregunta

Yo entiendo que esto puede ser interpretado como uno de los "¿Cuál es su preferencia" preguntas, pero me gustaría saber por qué se elija uno de los siguientes métodos sobre el otro.

Supongamos que tenemos un súper complejo clase, como por ejemplo:


class CDoSomthing {

    public:
        CDoSomthing::CDoSomthing(char *sUserName, char *sPassword)
        {
            //Do somthing...
        }

        CDoSomthing::~CDoSomthing()
        {
            //Do somthing...
        }
};

¿Cómo debo declarar una instancia local dentro de una función global?


int main(void)
{
    CDoSomthing *pDoSomthing = new CDoSomthing("UserName", "Password");

    //Do somthing...

    delete pDoSomthing;
}

- o -


int main(void)
{
    CDoSomthing DoSomthing("UserName", "Password");

    //Do somthing...

    return 0;
}
¿Fue útil?

Solución

Prefiero variables locales, a menos que necesite tiempo de vida del objeto para extenderse más allá del bloque actual. (Las variables locales son la segunda opción). Es más fácil de preocuparse por la gestión de memoria.

P.S. Si necesita un puntero, porque lo necesita para pasar a otra función, sólo tiene que utilizar el operador de dirección:

SomeFunction(&DoSomthing);

Otros consejos

Hay dos consideraciones principales cuando se declara una variable en el frente de pila en el montón -. De control de toda la vida y gestión de recursos

La asignación en la pila funciona muy bien cuando se tiene un control estricto sobre el tiempo de vida del objeto. Esto significa que no va a pasar un puntero o una referencia de ese objeto a código fuera del ámbito de la función local. Esto significa, no hay parámetros out, no hay llamadas COM, no hay nuevos temas. Bastantes de las limitaciones, pero se obtiene el objeto limpiado correctamente para que la salida normal o excepcional desde el ámbito actual (Sin embargo, es posible que desee leer sobre las reglas de la pila desenrollar con destructores virtuales). El mayor inconveniente de la asignación de pila -. La pila se limita generalmente a 4K 8K o, lo que podría querer tener cuidado con lo que usted pone en él

La asignación en el montón por el contrario se requeriría para la limpieza de la instancia manualmente. Esto también significa que usted tiene mucha libertad a controlar el tiempo de vida de la instancia. Es necesario hacer esto en dos escenarios: a) que va a pasar ese objeto fuera de su alcance; o b) el objeto es demasiado grande y su asignación en la pila podría causar desbordamiento de pila.

Por cierto, un buen compromiso entre estos dos está asignando el objeto en el montón y la asignación de un puntero inteligente a ella en la pila. Esto asegura que usted no está perdiendo memoria de pila preciosa, al mismo tiempo conseguir la limpieza automática en la salida ámbito de aplicación.

La segunda forma es la llamada RAII (Recursos de adquisición es de inicialización) patrón. Tiene muchas ventajas con respecto a la primera.

Cuando el uso new, usted tiene que utilizar delete a sí mismo, y garantizar que siempre será eliminado, incluso si se produce una excepción. Debe garantizar que todo usted mismo.

Si utiliza la segunda forma, cuando la variable se sale del ámbito, siempre se limpian automáticamente. Y si se produce una excepción, la pila se desenrolla y también se limpia.

Por lo tanto, se debe preferir RAII (la segunda opción).

Además de lo que se ha dicho hasta ahora, pero hay consideraciones de rendimiento adicionales que deben tenerse en cuenta, particularmente en aplicaciones de asignación de memoria-intensiva:

  1. Uso new asignará memoria del montón. En el caso de intensa (muy frecuente) la asignación y desasignación, usted tendrá que pagar un alto precio en:
    • Bloqueo: el montón es un recurso compartido por todos los hilos en su proceso. Las operaciones en el montón pueden requerir el bloqueo en el administrador del montón (hecho por usted en la biblioteca de tiempo de ejecución), lo que puede ralentizar las cosas de manera significativa.
    • fragmentación: fragmentos montón. Usted puede ver el tiempo que se tarda malloc / nuevo y libre / borrar para volver aumento de 10 veces. Esto agrava el problema de bloqueo anteriormente, ya que toma más tiempo para gestionar un montón fragmentada y más hilos hacen cola esperando la cerradura sanar. (En Windows existe una bandera especial que puede establecer para el administrador del montón por lo que heurísticamente los intentos de reducir la fragmentación.)
  2. Uso del patrón de RAII, la memoria es simplemente retirado de la pila. Stack es un recurso para cada subproceso, no se fragmenta, no hay bloqueo involucrados, y puede llegar a jugar en su ventaja en términos de localidad de memoria (es decir, el almacenamiento en caché de memoria a nivel de la CPU.)

Por lo tanto, cuando se necesita objetos para una breve (o cuyo ámbito) período de tiempo, sin duda utilizar el segundo método (variable local, en la pila.) Si necesita compartir datos entre hilos, el uso new/malloc (por un lado se tienen que, en la segunda parte, estos objetos son normalmente de larga duración suficiente para que pague esencialmente 0 costo vis-a-vis el administrador del montón.)

La segunda versión se desenrollar la pila si se produce una excepción. La primera no lo hará. No veo mucha diferencia lo contrario.

La mayor diferencia entre los dos es que el nuevo inicia un puntero al objeto.

Al crear el objeto sin nueva, iniciada el objeto se almacena en la pila. Si se inicia con el nuevo, devuelve un puntero al nuevo objeto que se ha creado en el montón. En realidad, devuelve una dirección de memoria que apunta al nuevo objeto. Cuando esto sucede, es necesario gestionar la memoria de la variable. Cuando haya terminado de usar la variable, lo que tendría que llamar a borrar en ella para evitar una pérdida de memoria. Sin el nuevo operador, cuando la variable se sale del ámbito de la memoria se libera automáticamente.

Así que si usted necesita para pasar la variable fuera del alcance actual, utilizando la nueva es más eficiente. Sin embargo, si usted necesita para hacer una variable temporal, o algo que sólo será utilizado temporalmente, teniendo el objeto en la pila va a ser mejor, ya que no tiene que preocuparse de la gestión de memoria.

Marcar Ransom es correcto, también tendrá que crear una instancia con new si se va a pasar la variable como parámetro a la función CreateThread-esque.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top