Приведение списка указателей к списку указателей на константы в C++

У меня есть класс, который должен создавать/поддерживать список указателей на объекты, но затем должен возвращать постоянный список постоянных указателей на одни и те же данные. Итак, что-то вроде:

class Foo {
private:
   std::list<Word *>  myList;
public:
   const std::list<const Word *>  getList() { return myList; }
}

Но если я это скомпилирую, то получу ошибку:

error: cannot convert 'const std::__cxx11::list<Word*>*' to 'const std::__cxx11::list<const Word*>*' in return

Есть ли способ привести список указателей к списку постоянных указателей?

AFAIK, это невозможно как таковое.

wohlstad 28.07.2024 15:48

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

Chukwujiobi Canon 28.07.2024 16:09
propagate const может быть тем, что вы ищете... Однако не уверен, какие компиляторы поддерживают это, MSVC - нет.
ChrisMM 28.07.2024 16:10

типы std::list<Word*> и std::list<Word const*> не связаны, между ними нельзя выполнить преобразование. Можно reinterpret_cast и const_cast, но будьте осторожны с побочными эффектами (по крайней мере, все они должны быть прямо и косвенно константными): reinterpret_cast<std::list<Word const*>const&>(myList).

dalfaB 28.07.2024 16:16

Также представьте, если бы это преобразование было стандартной практикой. Затем вы можете привести const std::list<Word*>* (A) к const std::list<const Word*>* (B) и изменить объекты Word через A, нарушив константную корректность B. Хорошо, что это не стандартная практика.

Chukwujiobi Canon 28.07.2024 16:19

Примечание. Зачем вообще использовать указатели (с правильной семантикой перемещения), вы можете просто использовать std::vector<Word>, а затем вернуть const std::vector<Word>& (другими словами, не используйте указатели, если вам действительно не нужно)

Pepijn Kramer 28.07.2024 16:32

@ChukwujiobiCanon — Вы можете сделать Word A("blah"); const Word *B = &A; A.set("blahblah"), у которого точно такая же проблема с константной корректностью, за исключением того, что это разрешено в C++. В моем случае я хочу иметь возможность изменять список, но не хочу, чтобы кто-либо, получающий список, мог с ним связываться...

user11809993 28.07.2024 17:25

Вы должны дать им новый список. Использование { return {myList.begin(), myList.end()}; } может сработать, сейчас не могу проверить.

NathanOliver 28.07.2024 17:39

@user11809993 user11809993 хорошо, что это не стандартная практика. Кроме того, в чем смысл возврата постоянного списка указателей на постоянные значения? В конце концов, это может быть проблема XY.

Chukwujiobi Canon 28.07.2024 18:14

Возврат по значению почти всегда лучше, чем возврат по константному значению. (Этот совет применим в области «по значению», которая сильно отличается от возврата по ссылке и возврата по константной ссылке, каждый из которых имеет общие сценарии использования.)

Eljay 28.07.2024 18:40

У меня есть программа с большой базой данных элементов, которые используются несколькими объектами в программе. У меня есть класс-производитель, который отвечает за динамическое создание списка, содержащего подмножество этих элементов (ему необходимо обновить каждый из элементов, чтобы отметить, к каким спискам они принадлежат, а также обновить статистику и т. д., поэтому ему требуется доступ для чтения и записи к каждый из предметов). Наконец, у меня есть несколько потребителей, которым нужно выполнять операции на основе этих списков. Потребители должны иметь доступ только для чтения к списку. Следовательно, я хочу передать константный список указателей на константные элементы каждому из потребителей.

user11809993 28.07.2024 19:47

Будет ли производитель манипулировать экземплярами Word через Word*? Что-то не так с тем, что продюсер также держит const Word* внутри std::list?

Chukwujiobi Canon 28.07.2024 19:49

@user11809993 user11809993 - затем верните копию списка с константными указателями, как кто-то предложил выше.

Gene 28.07.2024 20:08

@ChukwujiobiCanon да, он будет изменять каждую запись при ее размещении в списке (а также изменять каждую запись при ее удалении из списка). Производитель требует доступ на запись к каждому из элементов.

user11809993 28.07.2024 20:47

@Gene - каждый список содержит до 100 000 записей, поэтому я бы предпочел не копировать их. Я модифицирую всех потребителей, чтобы они принимали неконстантные указатели, и перед их использованием заставлю их приводить к константным указателям.

user11809993 28.07.2024 20:53

@user11809993 user11809993 - теперь это сбивает с толку, ваш исходный код пытался создать копию, но не скомпилировался, теперь вы говорите, что вам не нужна копия. Если вам не нужна копия, не возвращайте список, предоставьте функции для работы с элементами.

Gene 28.07.2024 22:50
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
16
111
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Есть ли способ привести список указателей к списку постоянных указателей?

Как буквально спросили, нет. list<T*> и list<T const *> не похожи так же, как T* и T const* похожи.

Если вы можете обобщить просто возврат чего-то итеративного (и вы используете достаточно современный C++), вы можете избежать копирования всего списка следующим образом:

auto getList() const
{
    return myList | std::views::transform(
        [](int *p) { return const_cast<int const *>(p); }
    );
}

В противном случае обычное решение — хранить в списке почти все, кроме необработанных указателей.

Подойдет все, что имеет const-квалифицированные методы, которые правильно передают константность от константного итератора до конечного объекта - есть несколько примеров по этому довольно старому вопросу, или вы можете найти реализации std::experimental: :propagate_const.

Если у вас есть доступ к диапазонам, следует отдать предпочтение ответу @Useless. Другие альтернативы:

  • Если вам нужно вернуть только итерируемый объект, вы можете создать собственный тип итератора, который возвращает указатель const.
  • Или вы можете сохранить std::list<const Word *> внутри Foo и использовать const_cast для доступа к неконстантному указателю внутри реализации Foo.

Другие вопросы по теме