Я пытаюсь понять, как boost::make_shared
выполняет выделение памяти для объекта, управляемого boost::shared_ptr
и объект подсчета ссылок (совместно используемый shared_ptr
).
Функция make_shared
начинает выполнение здесь:
template< class T, class A1, class A2, class A3 >
typename boost::detail::sp_if_not_array< T >::type make_shared( A1 && a1, A2 && a2, A3 && a3 )
{
//Seems to create the smart_ptr for the object
boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) );
//Not sure?
boost::detail::sp_ms_deleter< T > * pd = static_cast<boost::detail::sp_ms_deleter< T > *>( pt._internal_get_untyped_deleter() );
//Calculates the address at which the bulk-allocation begins
void * pv = pd->address();
//Allocates the memory at address pv?
::new( pv ) T(
boost::detail::sp_forward<A1>( a1 ),
boost::detail::sp_forward<A2>( a2 ),
boost::detail::sp_forward<A3>( a3 )
);
//Not sure
pd->set_initialized();
//Not sure
T * pt2 = static_cast< T* >( pv );
//Not sure
boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 );
return boost::shared_ptr< T >( pt, pt2 );
}
Кто-нибудь сможет объяснить оставшиеся строки?
Я пытаюсь определить, где определяется размер распределения объемной памяти (объект, на который указывают, и объект подсчета ссылок shared_ptr)?
Что меня бросает, так это то, что вызов address()
, по-видимому, не учитывает размер объекта T
при распределении адреса для размещения.
(Я действительно не понимаю, какие три параметра AX
входят в метод и передаются на вызов new()
места размещения)
Пусть берется линия за строкой
boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) );
Это создает общий указатель, но ключ здесь является делетером. BOOST_SP_MSD(T)
- это макрос, который разрешает делетиру с достаточным пространством для ваших данных. Таким образом, блок подсчета ссылок общего указателя также содержит пространство для делетера, которое теперь включает в себя пространство для вашего T
//Not sure?
boost::detail::sp_ms_deleter< T > * pd = static_cast<boost::detail::sp_ms_deleter< T > *>( pt._internal_get_untyped_deleter() );
Это получает адрес отправителя из общего указателя. Это будет указывать на создателя, созданного выше.
//Calculates the address at which the bulk-allocation begins
void * pv = pd->address();
Это возвращает начальный адрес для типа T
, который в настоящее время неинициализирован и является частью deleter
//Allocates the memory at address pv?
::new( pv ) T(
boost::detail::sp_forward<A1>( a1 ),
boost::detail::sp_forward<A2>( a2 ),
boost::detail::sp_forward<A3>( a3 )
);
Это новое место размещения. Это создает ваш T
по адресу, указанному в pv
. Он передает 3 аргумента, потому что это 3-arg версия make_shared
.
//Not sure
pd->set_initialized();
Это внутренний флаг в deleter, который позволяет ему знать, что T
был сконструирован (так что, когда вызывается operator()
deleter operator()
, он уничтожит его)
//Not sure
T * pt2 = static_cast< T* >( pv );
Это отличает void * выше в T*
. Честно говоря, я не уверен, почему они просто не сохранили результат размещения нового.
//Not sure
boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 );
Это необходимо для обеспечения возможности enable_shared_from_this
. Эта внутренняя функция устанавливает базовый механизм для enable_shared_from_this
. Обычно это называется, когда вы помещаете что-то в shared_ptr
return boost::shared_ptr< T >( pt, pt2 );
Это фактически создает новый boost::shared_ptr
который использует ту же область подсчета ссылок, что и pt
, но его методы get()
и связанные с ним методы возвращают pt2
, который является указателем на T
, который хранится в deleter.