У меня есть некоторая путаница в конструкторе копирования shared_ptr. Пожалуйста, рассмотрите следующие 2 строки:
Это «постоянная» ссылка на объект shared_ptr, который передается конструктору копирования для инициализации другого объекта shared_ptr.
Предполагается, что конструктор копирования также увеличивает данные-члены — «счетчик ссылок», который также используется всеми объектами shared_ptr, потому что это ссылка / указатель на некоторое целое число, сообщающее каждому объекту shared_ptr, сколько из них еще в живых.
Но если конструктор копирования пытается увеличить данные элемента подсчета ссылок, не «ударит» ли он по константе shared_ptr, переданного по ссылке? Или конструктор копирования внутренне использует оператор const_cast для временного удаления константы аргумента?
Феномен, который вы испытываете, не является особенным для общего указателя. Вот типичный первобытный пример:
struct Foo
{
int * p;
Foo() : p(new int(1)) { }
};
void f(Foo const & x) // <-- const...?!?
{
*x.p = 12; // ...but this is fine!
}
Правда, что x.p
имеет тип int * const
внутри f
, но это не int const * const
! Другими словами, вы не можете изменить x.p
, но ты Можно менять *x.p
,
По сути, это то, что происходит в конструкторе копирования общего указателя (где *p
берет на себя роль контрольного счетчика).
Хотя другие ответы верны, может быть не сразу видно, как они применяются. У нас есть что-то вроде этого:
template <class T>
struct shared_ptr_internal {
T *data;
size_t refs;
};
template <class T>
class shared_ptr {
shared_ptr_internal<T> *ptr;
public:
shared_ptr(shared_ptr const &p) {
ptr = p->ptr;
++(ptr->refs);
}
// ...
};
Важным моментом здесь является то, что shared_ptr просто содержит указатель в структура, которая содержит счетчик ссылок. Тот факт, что shared_ptr
сам по себе const
не влияет на объект, на который он указывает (то, что я назвал shared_ptr_internal
). Таким образом, даже когда / если shared_ptr
сам по себе const
манипулирование счетчиком ссылок не является проблемой (и не требует const_cast
или же mutable
или).
Я, вероятно, должен добавить, что в действительности вы, вероятно, структурировали бы код немного иначе, чем этот — в частности, вы обычно помещали бы больше (все?) Кода для манипулирования счетчиком ссылок в shared_ptr_internal (или что бы то ни было решаю так называть) сам, вместо того чтобы возиться с тем у родителя shared_ptr
учебный класс.
Вы также обычно поддерживаете weak_ptr
s. Для этого у вас есть второй счетчик ссылок на количество weak_ptr
это указывает на то же самое shared_ptr_internal
объект. Вы уничтожаете последний объект, когда shared_ptr
отсчет идет до 0, но уничтожает только shared_ptr_internal
объект, когда оба shared_ptr
а также weak_ptr
счетчик ссылок идет к 0.
Он использует внутренний указатель, который не наследует конкурсы аргумента, например:
(*const_ref.member)++;
Является действительным.
указатель является постоянным, но не указанным значением.
Вау, что это за сенсация! Спасибо всем, что я смог определить источник путаницы в том факте, что я всегда предполагал, что следующее («a» содержит адрес «b») было эквивалентно.
int const *a = &b; // option1
const int *a = &b; // option2
int * const a = &b; // option3
Но я был неправ! Только первые два варианта эквивалентны. Третий совершенно другой.
С опцией 1 или опцией 2 «а» может указывать на все, что он хочет, но не может изменять содержимое того, на что он указывает.
С опцией 3, однажды решив, на что указывает «а», он не может указать ни на что другое. Но он может свободно изменять содержимое того, на что он указывает. Таким образом, имеет смысл, что shared_ptr использует option3.