Russian Qt Forum
Июнь 01, 2024, 12:30 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2 3   Вниз
  Печать  
Автор Тема: mutable метод?  (Прочитано 13240 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Апрель 04, 2015, 13:19 »

Добрый день

Есть ли mutable методы - аналогично mutable членам? Сегодня опять столкнулся с этим неудобством, псевдокод
Код
C++ (Qt)
int MyClass::GetNumFiles( void ) const  // ну явно const, возвращает инфу
{
 if (mData.size() == 0)    // данные были сброшены?
  UpdateData();              // пересоздать данные (никак не const)      
 
return mData.size();
}
 
Спасибо
Записан
Bepec
Гость
« Ответ #1 : Апрель 04, 2015, 16:51 »

Вроде бы нет. Но мутабл члены решат эту проблему.

PS но это явный и плохой костыль. От него надо избавляться.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Апрель 04, 2015, 17:15 »

Вроде бы нет. Но мутабл члены решат эту проблему.
Не вижу каким образом  Улыбающийся

PS но это явный и плохой костыль. От него надо избавляться.
Ну так, добросил фразу - авось "в масть", угадаю.
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #3 : Апрель 04, 2015, 17:51 »

снимите const с this
Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #4 : Апрель 04, 2015, 18:13 »

Igors, одна функция - одной действие.

функция, которая занимается тем,
что возвращает количество файлов не должна заниматься их обновлением.

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

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

Записан
Bepec
Гость
« Ответ #5 : Апрель 04, 2015, 22:24 »

Ммм... если все изменяемые члены будут мутаблами, конст метод должен скомпилиться, нет?

Нет, не добросил фразу, а прямо сказал что это костыль. Как и мутабл переменные - это костыль, которого в идеале быть не должно.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Апрель 05, 2015, 04:57 »

одна функция - одной действие.

функция, которая занимается тем,
что возвращает количество файлов не должна заниматься их обновлением.
Такая логика несколько прямолинейна Улыбающийся  Сделать 2 метода несложно, но тогда второй (напр UpdateFiles) быстро проникнет во все щели, его придется вызывать всем кто пользуется MyClass::GeetNumFiles и др такими геттерами (их там с десяток). И будет совсем непросто отследить был ли UpdateFiles перед вызовом каждого геттера. Замкнуть UpdateFiles в своем классе гораздо лучше, как бы "отложенное действие", что-там "lazy" - вещь типовая.

если по каким то соображениям вы решили все таки навесить на одну функцию несколько задач,
тогда будьте честны и убирайте квалификатор const с метода.
Да, формально, с точки зрения языка, GetNumFiles никакой не const. Но убрать const вызывает эффект домино, от константности остаются рожки да ножки. Теперь уже MyClass практически нигде не подать по константной ссылке - не даст первый геттер. И по смыслу неконстантность здесь не лепится, напр
Код
C++ (Qt)
void AnotherClass::DoSomething( MyClass & data )
{
...
data.UpdateFiles();
int count = data.GetNumFiles();
..
}
Выглядит как DoSomething предназначен чтобы сделать что-то с экземпляром MyClass - но в действительности он им просто пользуется

Придется наверное смириться с const_cast внутрях
Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #7 : Апрель 05, 2015, 06:35 »

И по смыслу неконстантность здесь не лепится, напр
Код
C++ (Qt)
void AnotherClass::DoSomething( MyClass & data )
{
...
data.UpdateFiles();
int count = data.GetNumFiles();
..
}
Выглядит как DoSomething предназначен чтобы сделать что-то с экземпляром MyClass - но в действительности он им просто пользуется

напротив. выглядит так, словно DoSomething хочет изменить состояние data
и по факту именно это и происходит.

есть логическое разделение: "только для чтения", и "для изменения".
ну так вот, и внешний дизайн DoSomething,
и её реализация указывают,
что она будет изменять объект.

логическое "только для чтения" - например, мы лочим мутекс, что бы прочитать данные.
для этого приходится делать мутекс mutable,
потому что он свое состояние меняет,
несмотря на то, что все что нам нужно - просто прочитать состояние агрегата.
однако после окончания операции чтения, мы мутекс разлочиваем, и он тоже принимает первоначальное состояние.

таким образом, логическое состояние не изменялось.
а бинарное состояние "до" и "после" осталось прежнем.






но в вашей ситуации - не просто чтение. вы реально обновляете компонент.
он у вас не только бинарно, но и логически тоже изменяется.
меняет состояние со "старого" на "обновленное".

пользуясь функцией DoSomething, я знаю, что после её запуска,
моя data может быть принципиально в другом состоянии, отличном от изначального.



а вот если бы она выглядела так, словно только для чтения,
а сама по факту меняла бы данные,
то это был бы сюрприз для стороннего программиста.


Придется наверное смириться с const_cast внутрях

ага. потом программер будет чесать репу:
почему так? объект не должен был измениться,
но мало того, что изменился, так ещё и покрашел весь процесс.

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

он же не знает, что там под капотом конст_каст снимает константность,
и затем состояние объекта изменяется.

он думает: ну раз функция якобы только для чтения,
и раз она принимает объект по константной ссылке, то значит не будет его изменять.

он очень удивится, и далеко не сразу поймет причину ошибки,
когда попытается вызвать такую функцию, скормив ей константный объект.


модификация объекта, рожденного константой - UB.
оптимизирующий компилятор запросто может поместить такой объект в область памяти только для чтения.

const_cast + modification = upppssss ...

-----------------------------------------------------

вы боретесь с последствиями ущербного дизайна.
и в попытке заставить его через палку работать,
готовы наставить таких костылей,
которые могут привести к трагичным последствиям.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Апрель 05, 2015, 07:18 »

напротив. выглядит так, словно DoSomething хочет изменить состояние data
и по факту именно это и происходит.

есть логическое разделение: "только для чтения", и "для изменения".
ну так вот, и внешний дизайн DoSomething,
и её реализация указывают,
что она будет изменять объект.
Опять-таки формально - да. Но посмотрим на это с точки зрения AnotherClass. Сколько раз он бы ни звал GetNumFiles (или любой др геттер) - рез-т тот же самый, для клиента ничего не меняется. А что там происходит внутри  MyClass - его личное дело, знание этих подробностей только вредит AnotherClass'у

вы боретесь с последствиями ущербного дизайна.
и в попытке заставить его через палку работать,
готовы наставить таких костылей,
которые могут привести к трагичным последствиям.
Сейчас сделано так: геттеры объявлены const, но практически все члены mutable. Этот дизайн мне кажется столь же ущербным как и const_cast. Но снимать const еще менее выгодно. Разумеется GetNumFiles virtual, а MyClass - только один из наследников большого базового класса. Если делать как Вы предложили, (строго следовать канонам), то вся эта иерархия классов практически полностью теряет константность.

Немного о предметной части. Есть "просто картинка" (файл). Есть "анимированная картинка" т.е. один файл хранит набор кадров. И есть набор файлов-картинок (напр 1.png, 2.png и.т.д) который тоже должен трактоваться как "картинка с кадрами".  Вот для клиента все это представляется одним классом
Записан
Old
Джедай : наставник для всех
*******
Online Online

Сообщений: 4349



Просмотр профиля
« Ответ #9 : Апрель 05, 2015, 07:29 »

А кто, как и почему может "сбросит" данные, после чего их приходится обновлять?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Апрель 05, 2015, 11:16 »

А кто, как и почему может "сбросит" данные, после чего их приходится обновлять?
Особо не вникал, один из вариантов - перегрузить текстуру (или все). Метод Reset просто зачищает контейнер, когда кто-то полезет за картинкой - перечитается. Возможно есть и др варианты. Изменить это в большом проекте непросто, да и работало без нареканий.
Записан
Old
Джедай : наставник для всех
*******
Online Online

Сообщений: 4349



Просмотр профиля
« Ответ #11 : Апрель 05, 2015, 11:33 »

Особо не вникал, один из вариантов - перегрузить текстуру (или все). Метод Reset просто зачищает контейнер, когда кто-то полезет за картинкой - перечитается. Возможно есть и др варианты.
Ну так метод reset и должен обновлять, он точно не const.

Изменить это в большом проекте непросто, да и работало без нареканий.
Если работало без нареканий, зачем туда лезть. Если что-то добавляете, то сделайте по аналогии с тем, как сделано там.
Это одним движением исправить все равно не получиться.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Апрель 05, 2015, 12:05 »

Ну так метод reset и должен обновлять, он точно не const.
Ну а чего ему всякий раз лезть сканировать файлы если это никому (пока) не нужно? В принципе у меня нет возражений против "lazy calculations"

Если работало без нареканий, зачем туда лезть. Если что-то добавляете, то сделайте по аналогии с тем, как сделано там. Это одним движением исправить все равно не получиться.
А я и не лезу - просто обдумываю/советуюсь как лучше сделать, ситуация-то типовая, наверняка еще не раз вылезет.
Записан
Old
Джедай : наставник для всех
*******
Online Online

Сообщений: 4349



Просмотр профиля
« Ответ #13 : Апрель 05, 2015, 12:15 »

А я и не лезу - просто обдумываю/советуюсь как лучше сделать, ситуация-то типовая, наверняка еще не раз вылезет.
Код
C++ (Qt)
int MyClass::GetNumFiles( void ) const  // ну явно const, возвращает инфу
{
 if (mData->size() == 0)    // данные были сброшены?
   mData->updateData();              // пересоздать данные (никак не const)
 return mData->size();
}
 
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #14 : Апрель 05, 2015, 13:36 »

Ну чего там скромничать с одним членом, тогда уж так
Код
C++ (Qt)
struct CTest {
CTest( void ) : mHook(this)
{
}
 
void Modify( void ) const
{
mHook->mA = 0;
}
 
CTest * mHook;
int mA;
};
 
Улыбающийся
Записан
Страниц: [1] 2 3   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.128 секунд. Запросов: 19.