LINUX.ORG.RU

C++: несовместимые по const геттеры

 


0

2

или О Нарушенных Обещаниях.

Добрейшего всем.

У меня есть вектор элементов кастомного класса Item, которые надо сортировать двумя способами: по размеру и по хэшу.
Для этого я делаю два соответствующих геттера:

long getSize() const;
unsigned char* getHash();
Обращаю внимание на то, что getHash() не const, так как он же генерирует хэш, если хэш не был установлен. Посчитать заранее все хэши слишком дорого.
[UPD]
Хэши хранятся в объектах, getHash() изменяет значение соответствующего приватного члена
[/UPD]
Дальше пишется функтор с параметром field, принимающим значение SIZE или HASH
struct cmpItem
и оператор
bool operator() ( const Item& left, const Item& right)
суть которого следующая
if ( field == SIZE ) return left.getSize() < right.getSize();
/* if ( field == HASH ) return left.getHash() < right.getHash(); */

Сортировка вектора по размеру

std::vector<Item> scroll;
...
std::sort( scroll.begin(), scroll.end(), cmpItem(SIZE) );
работает как задумано, а с сортировкой по хэшу проблемы.

Если раскомментить в функторе

if ( field == HASH ) return left.getHash() < right.getHash();
то компилятор жалуется:

passing ‘const Item’ as ‘this’ argument of ‘unsigned char* Item::getHash()’ discards qualifiers

что логично, ибо этот метод не костантный.
Если привести getSize() к аналогичному getHash() виду (без const)

long getSize();
и соответственно поправить оператор
bool operator() ( Item& left, Item& right)
то вываливается простыня ошибок, из которых наиболее вразумительны

no match for call to ‘(cmpItem) (Item&, const Item&)’
no match for call to ‘(cmpItem) (const Item&, Item&)’

У меня такие вызовы не используются, это желание компилятора «шоб було»?

Нельзя иметь один функтор для неизменяющего метода и изменяющего метода?
Если я должен оба метода сделать не константными, то как?

★★★★

Последнее исправление: Xenesz (всего исправлений: 4)

Перестал читать пост после этого:

Обращаю внимание на то, что getHash() не const, так как он же генерирует хэш, если хэш не был установлен. Посчитать заранее все хэши слишком дорого.

Казалось бы, mutable ровно для таких случаев существует, равзе нет?

devsdc ★★
()

Сделай getHash константным, а сам хеш — mutable

Gvidon ★★★★
()

const это логическая сущность. Она декларирует, что метод не меняет внутреннего состояния объекта. getHash не меняет внутреннее состояние, она тупо кеширует результат. так что метод getHash может/должен быть константным.

vtVitus ★★★★★
()

еще один ничего не понял.

anonymous
()
Ответ на: комментарий от vtVitus

метод не меняет внутреннего состояния объекта. getHash не меняет внутреннее состояние

Хэши хранятся в объектах, getHash() изменяет значение соответствующего приватного члена.

Xenesz ★★★★
() автор топика
Ответ на: комментарий от Xenesz

Именно для этого в языке существует mutable

Gvidon ★★★★
()
Ответ на: комментарий от Xenesz

какая разница кто в чём хранится. думай на уровне логики, а не на уровне кто/что меняет. кеширование не меняет состояние всё остальное не важно.

vtVitus ★★★★★
()

stackoverflow

Another example would be a class that computes a value the first time it is requested

Тащемта мой случай например.

stackoverflow

but, to be honest, it feels like a bit of a hack

Xenesz ★★★★
() автор топика
Ответ на: комментарий от Xenesz

Не читайте советских газет...все верно тебе сказали. mutable придумали не просто так.

anonymous
()
Ответ на: комментарий от Xenesz

stackoverflow

Всем делать «Ку».

but, to be honest, it feels like a bit of a hack

И ему разжевали ровно то же, что пытаются вдолбить тебе.

anonymous
()
Ответ на: комментарий от Xenesz

как сказали выше - это решается через mutable, сам хеш (как и все кешируемое) не является частью состояния объекта.

return left.getHash() < right.getHash();

const вообще тут не при делах, ты пытаешься сравнить два указателя, подумай зачем тебе это надо. Ну и попутно расскажи нам что такое хэш в твоем контексте, и как его надо сравнивать

dib2 ★★★★★
()

Сделай метод константным, а поле, где хранится хэш, мутабельным. Всё должно быть окей.

При чём тут C++0x, не понял.

DELIRIUM ☆☆☆☆☆
()

Так или иначе, это работает.

Спасибо devsdc, Gvidon, vtVitus и anonymous.

Xenesz ★★★★
() автор топика
Ответ на: комментарий от DELIRIUM

При чём тут C++0x

Если новейшие плюшки могли как-то помочь, я не готов с ними разбираться.

Xenesz ★★★★
() автор топика

Посчитать заранее все хэши слишком дорого.

Если я не ошибаюсь, то std::sort пройдётся по всем елементам массива, и значит для каждого сгенерируется хеш. Так почему не сделать их заранее?

CyberK
()
unsigned char* getHash();
if ( field == HASH ) return left.getHash() < right.getHash();

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

CatsCantFly
()
long getSize() const;
void makeHash(); // или иное название, означающее вычисление и кеширование хеша
const unsigned char* getHash() const;

foreach(...) { makeHash(); }
sort(...);
andreyu ★★★★★
()

Кстати, а правда что сейчас за возврат сырого указателя из метода отрывают руки?

Macil ★★★★★
()
Ответ на: комментарий от Macil

Кстати, а правда что сейчас за возврат сырого указателя из метода отрывают руки?

Нет. Особенно, если это не владеющий указатель.

DarkEld3r ★★★★★
()
Ответ на: комментарий от CyberK

Если я не ошибаюсь, то std::sort пройдётся по всем елементам массива

Он пройдётся только по тем, которые имеют неуникальный размер.

Xenesz ★★★★
() автор топика
Ответ на: комментарий от CatsCantFly

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

Это заглушка, там вылезли непонятки, которые я не хотел тащить в этот пост.

Xenesz ★★★★
() автор топика
Ответ на: комментарий от CyberK

Кода в посте только огрызки, ибо простыня. Зато сказано: «Посчитать заранее все хэши слишком дорого.»

Xenesz ★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.