Как сделать глубокий константный указатель - PullRequest
2 голосов
/ 29 апреля 2020

Допустим, я хочу представить двоичное дерево в C ++. Обычно я хочу структуру Node, например:

struct Node {
  Node* left
  Node* right;
};

(здесь я использую struct и raw указатели просто для простоты. Я знаю, что я должен использовать умные указатели для управления памятью.)

У этого представления есть проблема: у меня никогда не может быть дерева с глубоким const. (Поправьте меня, если смогу.) Я могу отметить один Node const, но его дочерние элементы жестко закодированы как не-const в структуре Node.

(я могу использовать некоторые template взломать left и right опционально const, но это делает const Node и non- const Node несовместимыми.)

Вскоре я узнал, если я волшебным образом имел некоторый указатель глубины const (скажем, deep_const_pointer, что делает const ness транзитивным), я могу использовать этот указатель в Node, так что наличие узла const автоматически означает наличие субстанции const tree.

Я попытался написать класс указателя deep- const, и вот что я получаю в итоге:

template <typename T>
class deep_const_pointer {
public:
  explicit deep_const_pointer(const T* p_)
    : p{const_cast<T*>(p_)} {}

  const T& operator*() const { return *p; }
  T& operator*() { return *p; }

  const T* operator->() const { return p; }
  T* operator->() { return p; }

  // etc.

private:
  T* p;
};

Здесь я исключил const в конструкторе и, необязательно, добавьте его обратно в соответствии с const ness этого объекта, подобного указателю. Тем не менее, эта реализация допускает следующее:

const int i = 42;
deep_const_pointer<int> p{&i};
*p = 0; // Oops!

Таким образом, от пользователя зависит, правильно ли будет указывать, является ли указатель const или нет.

Как мне построить Deep- const указатель класса? В идеале я хочу, чтобы проверка const происходила во время компиляции, и этот класс указателя занимает столько же памяти, сколько необработанный указатель. (Что исключает решение для сохранения const ness в bool переменной-члене и проверки при каждом доступе.)

EDIT : я проверил std::experimental::propagate_const, и это на самом деле это не "глубокий" указатель с моей точки зрения. Я имею в виду глубокий константный указатель P:

  1. Константа P является указателем на константу;
  2. Изменяемый P является указателем на изменяемый;
  3. Константная ссылка на неконстантную P обрабатывается так, как если бы она была константой P;
  4. Поскольку указатель на-const имеет семантику значений, const P должно быть тривиально копируемым.

propagate_const не соответствует требованию, потому что:

  1. Он никогда не принимает указатель на константу;
  2. Это не подлежит копированию (конструкторы копирования явно удалены);

Судя по полученным комментариям и ответам, я думаю, что такой P не реализуем в C ++.

1 Ответ

0 голосов
/ 29 апреля 2020

Запись транзитивного - const интеллектуального указателя - это решенная проблема, просто посмотрите вверх std::experimental::propagate_const<>. Найти подходящие реализации не должно быть слишком сложно.

В своей собственной попытке вы ошиблись в конструировании необработанного указателя. Вы не должны добавлять const к типу pointee или раздевать его с помощью приведения.
Исправлено:

explicit deep_const_pointer(T* p_)
    : p{p_} {}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...