c++ - shared_ptr example
¿Std:: make_shared() usa asignadores personalizados? (2)
Considere este código :
#include <memory>
#include <iostream>
class SomeClass {
public:
SomeClass() {
std::cout << "SomeClass()" << std::endl;
}
~SomeClass() {
std::cout << "~SomeClass()" << std::endl;
}
void* operator new(std::size_t size) {
std::cout << "Custom new" << std::endl;
return ::operator new(size);
}
void operator delete(void* ptr, std::size_t size) {
std::cout << "Custom delete" << std::endl;
::operator delete(ptr);
}
};
int main() {
std::shared_ptr<SomeClass> ptr1(new SomeClass);
std::cout << std::endl << "Another one..." << std::endl << std::endl;
std::shared_ptr<SomeClass> ptr2(std::make_shared<SomeClass>());
std::cout << std::endl << "Done!" << std::endl << std::endl;
}
Aquí está su salida:
Custom new
SomeClass()
Another one...
SomeClass()
Done!
~SomeClass()
~SomeClass()
Custom delete
Claramente, std::make_shared()
no llamó al new
operador, está usando un asignador personalizado. ¿Es este el comportamiento estándar para std::make_shared()
?
Para expandir la respuesta correcta de Mat, make_shared
se implementa típicamente asignando un objeto que contiene los shared_ptr
referencia shared_ptr
y un búfer de bytes sin inicializar:
template<typename T>
struct shared_count_inplace
{
long m_count;
long weak_count;
typename std::aligned_storage<sizeof(T)>::type m_storage;
// ...
};
Este es el tipo que se asignará en el montón, no su tipo, por lo que no se llama al new
tipo. Luego, su tipo se construirá usando una ubicación new
en la ubicación (void*)&m_storage
.
Sí, este es el comportamiento estándar. Desde el estándar (§20.7.2.2.6 shared_ptr creation ):
Efectos: Asigna memoria adecuada para un objeto de tipo T y construye un objeto en esa memoria a través de la nueva expresión de ubicación
::new (pv) T(std::forward<Args>(args)...).
Esto permite que make_shared
asigne el almacenamiento tanto para el objeto como para la estructura de datos para el propio puntero compartido (el "bloque de control") en una sola asignación, por razones de eficiencia.
Podría usar std::allocate_shared
si desea controlar esa asignación de almacenamiento.