В чем разница между пустым и нулевым std:: shared_ptr в С++?
Страница cplusplus.com shared_ptr
вызывает различие между пустым std::shared_ptr
и нулевым shared_ptr
. На странице cppreference.com явно не указано различие, но в описании поведения std::shared_ptr
используется как "пустое", так и сравнение с nullptr
.
Есть ли разница между пустым и нулевым shared_ptr
? Есть ли какой-либо прецедент для таких указателей со смешанным поведением? Имеет ли смысл не пустой номер null shared_ptr
? Был бы когда-нибудь случай при обычном использовании (т.е. Если вы явно не построили его), где вы могли бы получить пустой, но не нулевой shared_ptr
?
И если любой из этих ответов изменится, если вы используете версию Boost вместо версии С++ 11?
Ответы
Ответ 1
Это странный угол поведения shared_ptr
. Он имеет конструктор, который позволяет вам сделать shared_ptr
, который владеет чем-то, и указывает на что-то еще:
template< class Y >
shared_ptr( const shared_ptr<Y>& r, T *ptr );
shared_ptr
, построенный с использованием этого конструктора, имеет право собственности на r
, но указывает на то, что указывает ptr
(т.е. вызов get()
или operator->()
вернет ptr
). Это удобно для случаев, когда ptr
указывает на подобъект (например, элемент данных) объекта, принадлежащего r
.
На странице, с которой вы связываете вызовы, shared_ptr
, которому нет ничего пустого, и shared_ptr
, который указывает на ничего (т.е. чей get() == nullptr
) null. (Пустой используется в этом смысле по стандарту, null - нет.) Вы можете построить пустой, но не пустой shared_ptr
, но это будет не очень полезно. Пустой, но не нулевой shared_ptr
по существу является не владеющим указателем, который может использоваться для выполнения некоторых странных вещей, таких как передавая указатель на что-то, выделенное в стеке, на функция, ожидающая shared_ptr
(но я бы предложил перфорировать того, кто сначала помещает shared_ptr
в API).
boost::shared_ptr
также имеет этот конструктор, который они называют конструктором псевдонимов.
Ответ 2
Есть ли разница между пустым и null shared_ptr?
Пусто shared_ptr
не имеет контрольного блока, а его счет использования считается равным 0. Копия пустого shared_ptr
- еще одна пустая shared_ptr
. Они оба являются отдельными shared_ptr
, которые не имеют общего блока управления, потому что у него его нет. Пустой shared_ptr
можно построить с помощью конструктора по умолчанию или с конструктором, который принимает nullptr
.
Непустой null shared_ptr
имеет блок управления, который может использоваться совместно с другими shared_ptr
s. Копия непустого null shared_ptr
- это shared_ptr
, который имеет тот же блок управления, что и исходный shared_ptr
, поэтому использование count не равно 0. Можно сказать, что все копии shared_ptr
имеют один и тот же nullptr
. Непустой null shared_ptr
может быть создан с нулевым указателем типа объекта (не nullptr
)
Вот пример:
#include <iostream>
#include <memory>
int main()
{
std::cout << "std::shared_ptr<int> ptr1:" << std::endl;
{
std::shared_ptr<int> ptr1;
std::cout << "\tuse count before copying ptr: " << ptr1.use_count() << std::endl;
std::shared_ptr<int> ptr2 = ptr1;
std::cout << "\tuse count after copying ptr: " << ptr1.use_count() << std::endl;
std::cout << "\tptr1 is " << (ptr1 ? "not null" : "null") << std::endl;
}
std::cout << std::endl;
std::cout << "std::shared_ptr<int> ptr1(nullptr):" << std::endl;
{
std::shared_ptr<int> ptr1(nullptr);
std::cout << "\tuse count before copying ptr: " << ptr1.use_count() << std::endl;
std::shared_ptr<int> ptr2 = ptr1;
std::cout << "\tuse count after copying ptr: " << ptr1.use_count() << std::endl;
std::cout << "\tptr1 is " << (ptr1 ? "not null" : "null") << std::endl;
}
std::cout << std::endl;
std::cout << "std::shared_ptr<int> ptr1(static_cast<int*>(nullptr))" << std::endl;
{
std::shared_ptr<int> ptr1(static_cast<int*>(nullptr));
std::cout << "\tuse count before copying ptr: " << ptr1.use_count() << std::endl;
std::shared_ptr<int> ptr2 = ptr1;
std::cout << "\tuse count after copying ptr: " << ptr1.use_count() << std::endl;
std::cout << "\tptr1 is " << (ptr1 ? "not null" : "null") << std::endl;
}
std::cout << std::endl;
return 0;
}
Он выводит:
std::shared_ptr<int> ptr1:
use count before copying ptr: 0
use count after copying ptr: 0
ptr1 is null
std::shared_ptr<int> ptr1(nullptr):
use count before copying ptr: 0
use count after copying ptr: 0
ptr1 is null
std::shared_ptr<int> ptr1(static_cast<int*>(nullptr))
use count before copying ptr: 1
use count after copying ptr: 2
ptr1 is null
http://coliru.stacked-crooked.com/a/54f59730905ed2ff