util.smartptr.shared.const / 9 en C ++ 11:
Efectos: construye un objeto shared_ptr que posee el objeto p y el eliminador d. Los constructores segundo y cuarto deberán usar una copia de a para asignar memoria para uso interno.
El segundo y cuarto constructores tienen estos prototipos:
template<class Y, class D, class A> shared_ptr(Y* p, D d, A a);
template<class D, class A> shared_ptr(nullptr_t p, D d, A a);
En el último borrador, util.smartptr.shared.const / 10 es equivalente para nuestro propósito:
Efectos: construye un objeto shared_ptr que posee el objeto p y el eliminador d. Cuando T no es un tipo de matriz, los constructores primero y segundo habilitan shared_from_this con p. Los constructores segundo y cuarto deben usar una copia de a para asignar memoria para uso interno. Si se produce una excepción, se llama d (p).
Por lo tanto, el asignador se usa si es necesario asignarlo en la memoria asignada. Basado en el estándar actual y en los informes de defectos relevantes, la asignación no es obligatoria sino asumida por el comité.
Aunque la interfaz de shared_ptr
permite a una aplicación donde nunca hay un bloque de control y todo shared_ptr
y weak_ptr
se ponen en una lista enlazada, no hay tal aplicación en la práctica. Además, la redacción se ha modificado suponiendo, por ejemplo, que use_count
se comparte.
Se requiere que el eliminador solo se mueva de forma constructiva. Por lo tanto, no es posible tener varias copias en el shared_ptr
.
Uno puede imaginar una implementación que coloca al eliminador en un diseño especial shared_ptr
y lo mueve cuando se shared_ptr
elimina el especial . Si bien la implementación parece conforme, también es extraño, especialmente porque puede ser necesario un bloque de control para el recuento de uso (quizás sea posible pero incluso más extraño hacer lo mismo con el recuento de uso).
DR relevantes que encontré: 545 , 575 , 2434 (que reconocen que todas las implementaciones están usando un bloque de control y parecen implicar que las restricciones de subprocesos múltiples lo obligan de alguna manera), 2802 (que requiere que el eliminador solo se mueva de manera constructiva y, por lo tanto, impide la implementación donde El eliminador se copia entre varios shared_ptr
.
a
) para desasignar esa memoria. Lo que implicaría algún almacenamiento de esa copia dea
. No hay información al respecto en [util.smartptr.shared.dest].Desde std :: shared_ptr tenemos:
Y de std :: allocate_shared obtenemos:
Por lo tanto, parece que std :: allocate_shared debería asignar el
deleter
con suAlloc
.EDITAR: Y desde
n4810
§20.11.3.6 Creación [util.smartptr.shared.create][El énfasis es todo mío]
Entonces, el estándar dice que
std::allocate_shared
debería usarseAlloc
para el bloque de control.fuente
n4810
Respuesta encontrada y actualizada.make_shared
, no los constructores en sí. Aún así, puedo usar un miembro para pequeños borradores.Creo que esto no está especificado.
Aquí está la especificación de los constructores relevantes: [util.smartptr.shared.const] / 10
Ahora, mi interpretación es que cuando la implementación necesita memoria para uso interno, lo hace mediante el uso
a
. No significa que la implementación tenga que usar esta memoria para colocar todo. Por ejemplo, supongamos que existe esta implementación extraña:¿Esta implementación "utiliza una copia de
a
para asignar memoria para uso interno"? Si lo hace. Nunca asigna memoria excepto mediante el usoa
. Hay muchos problemas con esta implementación ingenua, pero digamos que cambia al uso de asignadores en todos los casos, excepto en el caso más simple, en el queshared_ptr
se construye directamente desde un puntero y nunca se copia, mueve o hace referencia de otro modo y no hay otras complicaciones. El punto es que el hecho de que no podamos imaginar una implementación válida no prueba por sí sola que no pueda existir teóricamente. No estoy diciendo que tal implementación se pueda encontrar realmente en el mundo real, solo que el estándar no parece estar prohibiéndola activamente.fuente
shared_ptr
para tipos pequeños asigna memoria en la pila. Y así no cumple con los requisitos estándarstd::move(__d)
, y recurra aallocate
cuando se requiere copia.