smart shared_ptr c++ c++14 smart-pointers

c++ - shared_ptr - ¿Por qué std:: make_unique en lugar de std:: unique_ptr:: make?



c++14 smart-pointers (3)

No hay una razón concreta aparte de la convención sola: una función de clase estática puede hacer todo lo que puede hacer una función global (funcionalidad inteligente).
C ++ prefiere las funciones globales (para funciones de utilidad) que se encuentran dentro de un espacio de nombres definido.
Otros lenguajes de programación (como Java) prefieren las funciones públicas estáticas, ya que las funciones globales no son compatibles.

esto no es nuevo para make_*** , existen otros ejemplos:

std::this_thread::XXXX lugar de std::thread::XXXX_current
aunque podría tener sentido poner una función que se relaciona con el subproceso de ejecución actual como funciones estáticas dentro de la clase de thread , se hacen globales dentro del espacio de nombres de este this_thread .

también, podríamos tener algo como std::container::sort que std::container es una clase auxiliar para contenedores, pero en su lugar tenemos std::sort .

¿Por qué C ++ adoptó funciones gratuitas para:

std::make_unique(...); std::make_shared(...);

En lugar de usar funciones miembro estáticas:

std::unique_ptr::make(...); // static std::shared_ptr::make(...); // static

?


TL; DR: las funciones miembro estáticas siempre tienen acceso a datos privados, pero las funciones gratuitas solo tienen acceso a datos privados cuando se marcan explícitamente como friend . La elección de implementar estas funciones como funciones gratuitas (con un pequeño número implementado como funciones de amistad) no es un artefacto histórico aleatorio, sino una decisión deliberada para mejorar la encapsulación mientras se tiene un esquema de nombres coherente para todos los std::make_x funciones

Hay muchas funciones estándar de fábrica en C ++:

std::make_pair std::make_tuple std::make_unique std::make_shared //efficiency std::make_exception_ptr //efficiency std::make_move_iterator std::make_reverse_iterator std::make_error_code std::make_error_condition //And several more are proposed for C++17

Por todo lo anterior, la función make_x se puede implementar correctamente utilizando solo la interfaz pública de x . En el caso de make_shared y make_exception_ptr , la implementación más eficiente requeriría acceso a los datos internos de std::shared_ptr o std::exception_ptr . Todos los demás se pueden implementar utilizando solo la interfaz pública con cero penalización de rendimiento.

La implementación de estas funciones como funciones libres que no son de amigos reduce la cantidad de código que tiene acceso a las partes internas privadas del objeto ( una propiedad deseable , ya que cuando menos código tiene acceso a datos privados, hay menos lugares que deben ser auditados). operaciones que violan las invariantes del objeto, y menos lugares que potencialmente necesitan ser cambiados si cambian las partes internas del objeto).

Si make_shared fuera la única función de fábrica similar, podría tener sentido que sea una función miembro, pero como la mayoría de estas funciones no tienen que ser funciones de friend para funcionar de manera eficiente, make_shared también se implementa como una función gratuita, por ejemplo. el bien de la consistencia.

Este es el diseño correcto, ya que si las funciones de make_shared miembros estáticas se usaran de forma sistemática, en todos los casos, aparte de make_shared y make_exception_ptr , la función de miembro tendría inevitablemente un acceso excesivo a los datos privados del objeto x . Con el diseño estandarizado, el pequeño número de funciones make_x que necesitan acceso a datos privados se puede marcar como friend , y el resto respeta la encapsulación correctamente de forma predeterminada. Si se utilizara un make_x no miembro en algunos casos y un miembro estático en otros, la biblioteca estándar se volvería inconsistente y más difícil de aprender.


Consistencia

No creo que haya ninguna razón convincente para tener la sintaxis ::make lugar de la actual. Supongo que make_unique y make_shared se prefirieron a una función static ::make para mantener la coherencia con las funciones existentes std::make_pair y std::make_heap , que existían antes de C ++ 11.

Tenga en cuenta que std::make_pair tiene una gran ventaja: deduce automáticamente los tipos del par resultante de la llamada a la función:

auto p0 = std::make_pair(1, 1.f); // pair<int, float>

Si tuviéramos std::pair::make , tendríamos que escribir:

auto p1 = std::pair<int, float>::make(1, 1.f);

que derrota el propósito de make_pair .

  • Por lo tanto, asumo que make_unique y make_shared fueron elegidos porque los desarrolladores ya estaban acostumbrados a make_pair y funciones similares.

  • Se eligió make_pair lugar de pair::make para los beneficios mencionados anteriormente.