Подтвердить что ты не робот

Почему оператор unique_ptr-> не const-overloaded?

std::unique_ptr::operator-> имеет подпись

pointer operator->() const noexcept;

Итак, operator-> является константой, но возвращает переменный указатель. Это позволяет использовать код:

void myConstMemberFunction() const
{
    myUniquePtrMember->nonConstFunction();
}

Почему стандарт позволяет это, и каков наилучший способ предотвратить использование, как представлено выше?

4b9b3361

Ответ 1

Подумайте об этом как обычный указатель:

int * const i;

является указателем const для не const int. Вы можете изменить int, но не указатель.

int const * i;

является указателем не const для const int. Вы можете изменить указатель, но не int.


Теперь, для unique_ptr, вопрос о том, входит ли const внутрь или вне <>. Итак:

std::unique_ptr<int> const u;

похож на первый. Вы можете изменить int, но не указатель.

Что вы хотите:

std::unique_ptr<int const> u;

Вы можете изменить указатель, но не int. Или, возможно, даже:

std::unique_ptr<int const> const u;

Здесь вы не можете изменить указатель или int.


Обратите внимание, как я всегда ставил const справа? Это немного необычно, но необходимо иметь дело с указателями. const всегда относится к предмету сразу слева от него, то есть * (указатель const) или int. См. http://kuhllib.com/2012/01/17/continental-const-placement/.

Написание const int может привести вас к мысли int const * - это const - указатель на не const int, что неверно.

Ответ 2

Это повторяет семантику традиционных указателей. Указатель const - это указатель, который не может быть мутирован. Однако объект, на который он указывает, может.

struct bar {
  void do_bar() {}
};

struct foo {
  void do_foo() const { b->do_bar(); } // OK
  bar* const b;
};

Чтобы избежать мутации указателя, вам нужен эквивалент unique_ptr указателя const для const, или

const std::unique_ptr<const bar> b;