Внутри конструктора копирования shared_ptr

У меня есть некоторая путаница в конструкторе копирования shared_ptr. Пожалуйста, рассмотрите следующие 2 строки:

  1. Это «постоянная» ссылка на объект shared_ptr, который передается конструктору копирования для инициализации другого объекта shared_ptr.

  2. Предполагается, что конструктор копирования также увеличивает данные-члены — «счетчик ссылок», который также используется всеми объектами shared_ptr, потому что это ссылка / указатель на некоторое целое число, сообщающее каждому объекту shared_ptr, сколько из них еще в живых.

Но если конструктор копирования пытается увеличить данные элемента подсчета ссылок, не «ударит» ли он по константе shared_ptr, переданного по ссылке? Или конструктор копирования внутренне использует оператор const_cast для временного удаления константы аргумента?

2

Решение

Феномен, который вы испытываете, не является особенным для общего указателя. Вот типичный первобытный пример:

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 берет на себя роль контрольного счетчика).

5

Другие решения

Хотя другие ответы верны, может быть не сразу видно, как они применяются. У нас есть что-то вроде этого:

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_ptrs. Для этого у вас есть второй счетчик ссылок на количество weak_ptrэто указывает на то же самое shared_ptr_internal объект. Вы уничтожаете последний объект, когда shared_ptr отсчет идет до 0, но уничтожает только shared_ptr_internal объект, когда оба shared_ptr а также weak_ptr счетчик ссылок идет к 0.

3

Он использует внутренний указатель, который не наследует конкурсы аргумента, например:

(*const_ref.member)++;

Является действительным.

2

указатель является постоянным, но не указанным значением.

0

Вау, что это за сенсация! Спасибо всем, что я смог определить источник путаницы в том факте, что я всегда предполагал, что следующее («a» содержит адрес «b») было эквивалентно.

int const  *a = &b;    // option1
const int  *a = &b;    // option2
int * const a = &b;    // option3

Но я был неправ! Только первые два варианта эквивалентны. Третий совершенно другой.

С опцией 1 или опцией 2 «а» может указывать на все, что он хочет, но не может изменять содержимое того, на что он указывает.

С опцией 3, однажды решив, на что указывает «а», он не может указать ни на что другое. Но он может свободно изменять содержимое того, на что он указывает. Таким образом, имеет смысл, что shared_ptr использует option3.

0