Tengo una pregunta acerca de C++11 mejores prácticas. Cuando la limpieza de un shared_ptr, debo usar el reset() función con ningún parámetro, o debería establecer el shared_ptr a nullptr? Por ejemplo:

std::shared_ptr<std::string> foo(new std::string("foo"));
foo.reset();
foo = nullptr;

¿Hay alguna diferencia real, o hay ventajas/desventajas enfoque?

  • foo = {} también es una opción!
InformationsquelleAutor user1930581 | 2013-04-22

4 Comentarios

  1. 73

    ¿Hay alguna diferencia real, o hay ventajas/desventajas enfoque?

    Las dos alternativas son absolutamente equivalentes, en el sentido de que la segunda forma (foo = nullptr) se define en términos de la primera. De conformidad con el Párrafo 20.7.1.2.3/8-10 de C++11 Estándar:

     unique_ptr& operator=(nullptr_t) noexcept;

    8 Efectos: reset().

    9 Postcondición: get() == nullptr

    10 Devuelve: *this.

    Por lo tanto, sólo tienes que elegir la que hace que su intención más clara para usted. Personalmente, yo prefiero:

    foo = nullptr;

    Porque hace más evidente que queremos que el puntero a null. Como consejo general, sin embargo, tratan de minimizar las situaciones en las que debe explícitamente restablecer un puntero inteligente.


    Además, en lugar de utilizar new:

    std::shared_ptr<std::string> foo(new std::string("foo"));

    Considerar el uso de std::make_shared() cuando sea posible:

    auto foo = std::make_shared<std::string>("foo");
    • La programación orientada a objetos, gracias por la captura, yo no estaba prestando atención a la hora de escribir la cadena. Actualizada la pregunta para reflejar los cambios.
    • Yo personalmente uso nullptr por la misma razón indicada por @Andy Acechar. Pero trate de escribir su código para que el shared_ptr sale del ámbito.
    • Estoy de acuerdo con tus consejos
    • ¿Puede explicar por qué make_shared es preferido?
    • Excepción-seguridad y una menor asignación: para una discusión más detallada, véase, por ejemplo, esta respuesta.
    • Ok, tres años han pasado. Espero que alguien lea esto…me di cuenta de que la citación de la norma es que unique_ptr y también que no hay operator=(nullptr_t) método para shared_ptr. Es correcto, que nullptr serán fundidas para unique_ptr y, a continuación, a shared_ptr si puedo usar foo = nullptr?
    • Estoy desconcertado que una respuesta de la que habla acerca de una clase diferente sin siquiera reconocer que es tan altamente upvoted. Como @mdr dijo, y r0ng mostraron (aunque sin el suficiente detalle o la atención a la optimización), shared_ptr no tiene un operator=(nullptr_t), por lo que la asignación nullptr que se requiere una conversión. Probablemente podemos mostrar que no importa en optimizadas, pero decir que «Las dos alternativas son absolutamente equivalentes, en el sentido de que la segunda forma (foo = nullptr) se define en términos de la primera» parece totalmente equivocado

  2. 13

    Yo preferiría reset() como señales de la intención. Sin embargo, tratar de escribir el código de tal manera que usted no necesita explícitamente claro un shared_ptr<>, es decir, garantizar que un shared_ptr<> queda fuera del ámbito al que de otra manera claro.

    • Podría explicar la razón detrás de los consejos en contra de borrar el puntero? Es allí cualquier impacto en el rendimiento o «simplemente» no tener un puntero nulo todo?
    • No, no hay ningún impacto en el rendimiento. Simplemente, la necesidad de la frecuencia de compensación el puntero puede indicar un error de diseño.
  3. 2

    Que tienen un poco diferente si utiliza https://godbolt.org/ para comprobar

    mediante el uso de gcc(7.2)

    foo.reset();
    genera código de la asamblea

      lea rax, [rbp-32]
      mov rdi, rax
      call std::__shared_ptr<int, (__gnu_cxx::_Lock_policy)2>::reset()

    sin embargo,
    foo = nullptr;
    genera

      lea rax, [rbp-16]
      mov esi, 0
      mov rdi, rax
      call std::shared_ptr<int>::shared_ptr(decltype(nullptr))
      lea rdx, [rbp-16]
      lea rax, [rbp-32]
      mov rsi, rdx
      mov rdi, rax
      call std::shared_ptr<int>::operator=(std::shared_ptr<int>&&)
      lea rax, [rbp-16]
      mov rdi, rax
      call std::shared_ptr<int>::~shared_ptr()

    Crea una compartido puntero con nullptr, asignar el objeto recién creado para la variable y llama al destructor para destruir la cadena.

    Ya no sé cómo comprobar lo que sucedió en la función reset(). No puede ver que es más rápido.

    • Si compila tanto con -O2 usted verá que no hay ninguna diferencia en una versión de lanzamiento.
  4. -2

    Generalmente, punteros inteligentes pueden manejar por sí solos. Pero si usted necesita una solución, la reset() es, en mi opinión, su mejor apuesta.

    • Sólo el que se expresará una opinión no responde a la pregunta, que fundamentalmente incluye una solicitud para que el razonamiento: «¿hay alguna diferencia real, o hay ventajas/desventajas enfoque?«

Dejar respuesta

Please enter your comment!
Please enter your name here