У меня есть класс, который должен создавать/поддерживать список указателей на объекты, но затем должен возвращать постоянный список постоянных указателей на одни и те же данные. Итак, что-то вроде:
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
Есть ли способ привести список указателей к списку постоянных указателей?
Обязательная придирка, const Word*
не является постоянным указателем, Word* const
есть.
типы std::list<Word*>
и std::list<Word const*>
не связаны, между ними нельзя выполнить преобразование. Можно reinterpret_cast
и const_cast
, но будьте осторожны с побочными эффектами (по крайней мере, все они должны быть прямо и косвенно константными): reinterpret_cast<std::list<Word const*>const&>(myList)
.
Также представьте, если бы это преобразование было стандартной практикой. Затем вы можете привести const std::list<Word*>*
(A
) к const std::list<const Word*>*
(B
) и изменить объекты Word
через A
, нарушив константную корректность B
. Хорошо, что это не стандартная практика.
Примечание. Зачем вообще использовать указатели (с правильной семантикой перемещения), вы можете просто использовать std::vector<Word>
, а затем вернуть const std::vector<Word>&
(другими словами, не используйте указатели, если вам действительно не нужно)
@ChukwujiobiCanon — Вы можете сделать Word A("blah"); const Word *B = &A; A.set("blahblah")
, у которого точно такая же проблема с константной корректностью, за исключением того, что это разрешено в C++. В моем случае я хочу иметь возможность изменять список, но не хочу, чтобы кто-либо, получающий список, мог с ним связываться...
Вы должны дать им новый список. Использование { return {myList.begin(), myList.end()}; }
может сработать, сейчас не могу проверить.
@user11809993 user11809993 хорошо, что это не стандартная практика. Кроме того, в чем смысл возврата постоянного списка указателей на постоянные значения? В конце концов, это может быть проблема XY.
Возврат по значению почти всегда лучше, чем возврат по константному значению. (Этот совет применим в области «по значению», которая сильно отличается от возврата по ссылке и возврата по константной ссылке, каждый из которых имеет общие сценарии использования.)
У меня есть программа с большой базой данных элементов, которые используются несколькими объектами в программе. У меня есть класс-производитель, который отвечает за динамическое создание списка, содержащего подмножество этих элементов (ему необходимо обновить каждый из элементов, чтобы отметить, к каким спискам они принадлежат, а также обновить статистику и т. д., поэтому ему требуется доступ для чтения и записи к каждый из предметов). Наконец, у меня есть несколько потребителей, которым нужно выполнять операции на основе этих списков. Потребители должны иметь доступ только для чтения к списку. Следовательно, я хочу передать константный список указателей на константные элементы каждому из потребителей.
Будет ли производитель манипулировать экземплярами Word
через Word*
? Что-то не так с тем, что продюсер также держит const Word*
внутри std::list
?
@user11809993 user11809993 - затем верните копию списка с константными указателями, как кто-то предложил выше.
@ChukwujiobiCanon да, он будет изменять каждую запись при ее размещении в списке (а также изменять каждую запись при ее удалении из списка). Производитель требует доступ на запись к каждому из элементов.
@Gene - каждый список содержит до 100 000 записей, поэтому я бы предпочел не копировать их. Я модифицирую всех потребителей, чтобы они принимали неконстантные указатели, и перед их использованием заставлю их приводить к константным указателям.
@user11809993 user11809993 - теперь это сбивает с толку, ваш исходный код пытался создать копию, но не скомпилировался, теперь вы говорите, что вам не нужна копия. Если вам не нужна копия, не возвращайте список, предоставьте функции для работы с элементами.
Есть ли способ привести список указателей к списку постоянных указателей?
Как буквально спросили, нет. 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. Другие альтернативы:
std::list<const Word *>
внутри Foo
и использовать const_cast
для доступа к неконстантному указателю внутри реализации Foo.
AFAIK, это невозможно как таковое.