Здравствуйте, VTT, Вы писали:
VTT>Здравствуйте, _hum_, Вы писали:
__>>нет. и вы тоже не поняли значит. речь не о том, чтобы не модифицировать ЗАДАННЫЙ ЭКЗЕМПЛЯР, а о том, чтобы запретить модификацию ВСЕ ЭКЗЕМПЛЯРЫ, если код их модификации попадает "в нитку", которая запускается вызовом class_const-метода.
__>>иными словами компилятор должен действовать так:
__>>0) заводит стек функций __>>1) помещает в стек class_const-метод __>>2) пока стек не пуст, берет верхний элемент стека и для него анализирует тело функции: __>> 2.1) все указатели типа C_A* трактует как const C_A* и выдает ошибку, если с помощью них производится попытка модификации; __>> 2.2) если встретилась функция, то помещает в стек и переходит к 2); __>> 2.3) делает pop для стека. __>>3) анализ завершен
__>>(тут еще оговорки, конечно, для рекурсивных вызовов, но это тоже решаемо на этапе анализа — просто не надо добавлять в стек то, что уже раньше встречалось)
VTT>Запретить модификацию всех экземпляров можно в runtime — сделать в классе дополнительное статическое поле со счетчиком const обращений и кидать исключение, если при вызове не-const метода этот счетчик не 0.
неее, в рантайме это не дело.
VTT>А на этапе компиляции это сделать не получится, так как у компилятора может не быть реализации класса C_B (или это вообще голый интерфейс), и, соответственно, он не сможет определить наличие обращение к не-const экземплярам C_A в нем.
не совсем понял, в каком месте (и в какой ситуации) не пройдет описанный мною выше алгоритм?
Re: "class const - метод" - можно ли организовать?
Здравствуйте, _hum_, Вы писали:
__>Потому встал вопрос, есть ли в других языках или в новом стандарте с++ что-нибудь наподобие "class const — метода", который делает __>константными ЛЮБЫЕ this данного класса в своей области видимости, и тем самым предотвращает всякое изменение любого (а значит и заданного)объекта данного класса?
Может и есть, но в С++ это не возможно, так как можно взять указатель на память, где лежит данное, привести его void*, сериализовать в строку, передать в другую функцию, десерилизовать, разыменовать и изменить данное. Отследить данную цепочку в момент компиляции не возможно.
__>Это понадобилось, в частности, для того, чтобы на этапе компиляции отлавливать зацикливания.
Ловите зацикливания в рантайме: флажок и RAII — всё, что для этого нужно.
И каждый день — без права на ошибку...
Re[2]: "class const - метод" - можно ли организовать?
Здравствуйте, B0FEE664, Вы писали:
BFE>Здравствуйте, _hum_, Вы писали:
__>>Потому встал вопрос, есть ли в других языках или в новом стандарте с++ что-нибудь наподобие "class const — метода", который делает __>>константными ЛЮБЫЕ this данного класса в своей области видимости, и тем самым предотвращает всякое изменение любого (а значит и заданного)объекта данного класса?
BFE>Может и есть, но в С++ это не возможно, так как можно взять указатель на память, где лежит данное, привести его void*, сериализовать в строку, передать в другую функцию, десерилизовать, разыменовать и изменить данное. Отследить данную цепочку в момент компиляции не возможно.
ну, с таким подходом, так и const-спецификаторы невозможны, и в вобще ничего невозможно, кроме двочиных числе в ячеках памяти. речь же о том, чтобы дать возможность отслеживать НЕПРЕДНАМЕРЕННУЮ модификацию.
__>>Это понадобилось, в частности, для того, чтобы на этапе компиляции отлавливать зацикливания. BFE>Ловите зацикливания в рантайме: флажок и RAII — всё, что для этого нужно.
ага, особенно, если это система автопилота самолетом.
Re[3]: "class const - метод" - можно ли организовать?
Здравствуйте, B0FEE664, Вы писали:
BFE>Здравствуйте, _hum_, Вы писали:
__>>ага, особенно, если это система автопилота самолетом.
BFE>В системе автопилота самолета используется паттерн сигнал-слот? Не делайте так.
во-первых, вы так сказали, не я;
во-вторых, чем вас не устраивает сигнал-слот архитектура?
ну, а в-третьих, речь шла про общую проблему гарантии немодифицируемости методом полей объекта (решение которой, в частности, позволило бы решить проблему отслеживания циклов на этапе написания кода).
Re[5]: "class const - метод" - можно ли организовать?
Здравствуйте, _hum_, Вы писали:
__>во-вторых, чем вас не устраивает сигнал-слот архитектура?
Не устраивает двумя моментами:
1. Возможность возникновения event/signal loop. Невозможность доказать статически отсутсвие таких циклов.
2. Инфраструктура signal/slot занимает ресурсы. Как минимум память.
При условии наличия альтернативных механизмов свободных от 1 и 2 использование сигнал-слот представляется спорным.
Re[6]: "class const - метод" - можно ли организовать?
Здравствуйте, c-smile, Вы писали:
CS>Здравствуйте, _hum_, Вы писали:
__>>во-вторых, чем вас не устраивает сигнал-слот архитектура?
CS>Не устраивает двумя моментами:
CS>1. Возможность возникновения event/signal loop. Невозможность доказать статически отсутсвие таких циклов.
так а разве этим не грешат любые варианты организации двунаправленной связи между объектами?
CS>2. Инфраструктура signal/slot занимает ресурсы. Как минимум память.
CS>При условии наличия альтернативных механизмов свободных от 1 и 2 использование сигнал-слот представляется спорным.
а можно узнать об альтернативных механизмах, которые бы преодолевали эти два пункта, при том же самом функционале?
Re[5]: "class const - метод" - можно ли организовать?
Здравствуйте, _hum_, Вы писали:
__>>>ага, особенно, если это система автопилота самолетом. BFE>>В системе автопилота самолета используется паттерн сигнал-слот? Не делайте так. __>во-первых, вы так сказали, не я;
Я не предлагал использовать паттерн сигнал-слот для машин от которых может зависеть жизнь людей.
А что, собственно, я сказал? Я предложил добавить проверку времени исполнения. Проверка времени исполнения не может существенно замедлить код использующий сигнал-слот-архитектуру, так как на данный момент любая реализация этого патерна включает в себя приведение типа при каждом вызове слот-функции. А всякое такое приведение типа включает в себя проверку указателя на NULL во время приведения типа. Так что добавление проверки одного флажка не может существенно замедлить работу.
__>во-вторых, чем вас не устраивает сигнал-слот архитектура?
Тем, что сигнал-слот архитектура существенно повышает сложность понимания кода при одновременном снижении сложности разработки. Создаётся иллюзия, что эта архитектура упрощает код при фактическом его усложнении из-за динамического связывания вызовов функций. (Собственно то, что вам потребовалось такая хитрая проверка константности говорит именно об этом.) Упрощенно можно сказать, что эта архитектура приводит к тому, что вместо кода:
void f()
{
fun1();
fun2();
fun3();
fun4();
}
программист видит код:
void f()
{
...
}
где троеточие заменяется вызовами функций в самых произвольных местах проекта. Таким образом теряется локальность изменений и за изменениями становится сложно следить.
Если вы действительно хотите применить эту архитектуру для чего-то такого, от чего может зависеть жизнь людей, то вам жизненно необходимо вести документацию отображающую все деревья вызовов сигнал-слот.
__>ну, а в-третьих, речь шла про общую проблему гарантии немодифицируемости методом полей объекта (решение которой, в частности, позволило бы решить проблему отслеживания циклов на этапе написания кода).
Это ведь не единственная проблема данной архитектуры. Замените
void C_B::foo_B(void){ m_pA->set_x(10);}
на
void C_B::foo_B(void){ delete m_pA;}
и вы получите не менее эпический краш даже при гарантии немодифицируемости методом полей объекта.
И каждый день — без права на ошибку...
Re[13]: "class const - метод" - можно ли организовать?
0) заводит стек функций
__>не совсем понял, в каком месте (и в какой ситуации) не пройдет описанный мною выше алгоритм?
Да с самого начала. В общем случае у компилятора нет никакой возможности построить этот стек вызовов. Вот например: метод foo_B класса C_B вызывается через указатель на абстрактный базовый класс. О том, что вызвался метод именно в классе C_B мы можем узнать только в runtime.
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Re[6]: "class const - метод" - можно ли организовать?
Здравствуйте, B0FEE664, Вы писали:
BFE>где троеточие заменяется вызовами функций в самых произвольных местах проекта. Таким образом теряется локальность изменений и за изменениями становится сложно следить.
а по моему это типичный пример динамического связывания. с таким подходом, под подозрение должны попасть и виртуальные функции
а по сути дела такой подход позволяет внедрить что-то типа микросервисной архитектуры внутри одного приложения, когда одни модули предоставляю.т сервисы, другие их используют, и обе стороны работают соврешенно независимо, не пытаясь контролировать кто их вызывал или кого они вызвали "на другой стороне" шины
Люди, я люблю вас! Будьте бдительны!!!
Re[6]: "class const - метод" - можно ли организовать?
BFE>А что, собственно, я сказал? Я предложил добавить проверку времени исполнения. Проверка времени исполнения не может существенно замедлить код использующий сигнал-слот-архитектуру, так как на данный момент любая реализация этого патерна включает в себя приведение типа при каждом вызове слот-функции. А всякое такое приведение типа включает в себя проверку указателя на NULL во время приведения типа. Так что добавление проверки одного флажка не может существенно замедлить работу.
самый главный недостаток динамического проверки, что ошибки ловятся уже в процессе работы, а значит, прерывают нормальное течение программы. к тому же не все их можно самому предугадать и словить. вот потому-то и стараются как можно больше проверок возложить на компилятор.
__>>во-вторых, чем вас не устраивает сигнал-слот архитектура? BFE>Тем, что сигнал-слот архитектура существенно повышает сложность понимания кода при одновременном снижении сложности разработки. Создаётся иллюзия, что эта архитектура упрощает код при фактическом его усложнении из-за динамического связывания вызовов функций. (Собственно то, что вам потребовалось такая хитрая проверка константности говорит именно об этом.) Упрощенно можно сказать, что эта архитектура приводит к тому, что вместо кода: BFE>
BFE>где троеточие заменяется вызовами функций в самых произвольных местах проекта. Таким образом теряется локальность изменений и за изменениями становится сложно следить. BFE>Если вы действительно хотите применить эту архитектуру для чего-то такого, от чего может зависеть жизнь людей, то вам жизненно необходимо вести документацию отображающую все деревья вызовов сигнал-слот.
погодите-погодите, кто говорил, что речь идет о динамическом связывании? во многих случаях (в том числе в моем) можно обойтись и статическим (никаких виртуальных функций, никаких observer-pattern, — обычная "магия шаблонов". см., например, библиотеку boost). но от этого проблема не пропадает (что указывает на ее общий характер).
__>>ну, а в-третьих, речь шла про общую проблему гарантии немодифицируемости методом полей объекта (решение которой, в частности, позволило бы решить проблему отслеживания циклов на этапе написания кода). BFE>Это ведь не единственная проблема данной архитектуры. Замените BFE>
BFE>и вы получите не менее эпический краш даже при гарантии немодифицируемости методом полей объекта.
принципиальное отличие — вы можете и сами это проконтролировать (например, проверкой выполнения условия возможности удаления или использовать RAII). а вот отследить скрытые циклические зависимости, как в моем примере — это уже во многом неподъемная для программиста задача. потому и должен в этом случае приходить на помощь компилятор.
Re[14]: "class const - метод" - можно ли организовать?
Здравствуйте, VTT, Вы писали:
VTT>Здравствуйте, _hum_, Вы писали:
VTT>0) заводит стек функций
__>>не совсем понял, в каком месте (и в какой ситуации) не пройдет описанный мною выше алгоритм?
VTT>Да с самого начала. В общем случае у компилятора нет никакой возможности построить этот стек вызовов. Вот например: метод foo_B класса C_B вызывается через указатель на абстрактный базовый класс. О том, что вызвался метод именно в классе C_B мы можем узнать только в runtime.
кхм.. извиняюсь, а как, по-вашему, компилятор генерирует код, если он не в курсе, кто что будет вызывать?
может, давайте все-таки на конкретном примере, и я вместо компилятора попробую вам пройтись по алгоритму?
если брать мой первоначальный пример, и считать, что там
void foo_A(void)class_const;
то компилятор будет действовать так:
— первый раз пробегает по тексту программы и заносит себе в память информацию о том, какие функции в программе объявлены (какие у них сигнатуры), и где у каждой объявленной функции определение (текст тела функции);
— второй раз пробегает по тексту программы и, встретив декларацию функции "foo_A(void)class_const", заносит ее первой в стек;
а дальше по п. 2)
берет с вершины стека foo_A(void)class_const и переходит к ее телу (информация о том, где оно , уже имеется после первого прохода):
void C_A::foo_A(void)const
{
m_pB->foo_B();
}
в теле видит вызов функции void foo_B(void), потому заносит его сигнатуру в стек; и т.д.
в каком месте он может споткнуться?
upd. может, вы имели в виду виртуальные функции? ну, так о них пока речь не шла (там можно либо все проверять, либо договориться, что в таких случаях виртуальные использовать нельзя).
Здравствуйте, _hum_, Вы писали:
__>кхм.. извиняюсь, а как, по-вашему, компилятор генерирует код, если он не в курсе, кто что будет вызывать?
Для компиляции ему вполне достаточно знать сигнатуру метода и откуда он берется (содержится в этом же исполняемом файле или импортируется).
__>- первый раз пробегает по тексту программы и заносит себе в память информацию о том, какие функции в программе объявлены (какие у них сигнатуры), и где у каждой объявленной функции определение (текст тела функции);
Дело в том, что как раз определения функции (текст тела функции) во время компиляции у компилятора может и не быть (я бы даже сказал что обычно нет).
Вот представьте, что класс C_B делает кто-то другой, а вам дает только заголовочный файл с объявлением этого класса и .dll (.lib) с его реализацией. А кода тела функции нет. И так со всеми системными и библиотечными функциями.
Даже если у вас есть код функции, он будет виден компилятору только если она inline или проект собирается с LTCG.
__>upd. может, вы имели в виду виртуальные функции? ну, так о них пока речь не шла (там можно либо все проверять, либо договориться, что в таких случаях виртуальные использовать нельзя).
Виртуальные я тоже имел ввиду. В начале вы вроде как упоминали сигнал-слоты, и на ум сразу приходит qt с его qobject и повальной виртуальностью.
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Re[16]: "class const - метод" - можно ли организовать?
Здравствуйте, VTT, Вы писали:
VTT>Здравствуйте, _hum_, Вы писали:
__>>- первый раз пробегает по тексту программы и заносит себе в память информацию о том, какие функции в программе объявлены (какие у них сигнатуры), и где у каждой объявленной функции определение (текст тела функции);
VTT>Дело в том, что как раз определения функции (текст тела функции) во время компиляции у компилятора может и не быть (я бы даже сказал что обычно нет). VTT>Вот представьте, что класс C_B делает кто-то другой, а вам дает только заголовочный файл с объявлением этого класса и .dll (.lib) с его реализацией. А кода тела функции нет. И так со всеми системными и библиотечными функциями. VTT>Даже если у вас есть код функции, он будет виден компилятору только если она inline или проект собирается с LTCG.
ну, разве только если с dll, потому как при статической компоновке (.lib) теоретически есть возможность перед построение окончательного кода, просмотреть библиотеки (почему-то интуитивно кажется, что выполнить алгоритм можно и по ассемблерному коду, зная изначально, какие типы участвуют в сигнатуре. а если и нет, то на будущее можно просто добавлять в них необходимую информацию).
но вообще, контраргумент понял — данное понятие на текущий момент не допускает раздельной компиляции...
__>>upd. может, вы имели в виду виртуальные функции? ну, так о них пока речь не шла (там можно либо все проверять, либо договориться, что в таких случаях виртуальные использовать нельзя).
VTT>Виртуальные я тоже имел ввиду. В начале вы вроде как упоминали сигнал-слоты, и на ум сразу приходит qt с его qobject и повальной виртуальностью.
не, я не люблю виртуальность, потому пока стараюсь обходиться статическим вариантом реализации сигналов-слотов (boost::signals2, да и qt ввел уже возможность статической реализации).
Re: "class const - метод" - можно ли организовать?
Здравствуйте, _hum_, Вы писали:
__>Потому встал вопрос, есть ли в других языках или в новом стандарте с++ что-нибудь наподобие "class const — метода", который делает константными ЛЮБЫЕ this данного класса в своей области видимости, и тем самым предотвращает всякое изменение любого (а значит и заданного)объекта данного класса?
Навесить константность на все объекты теоретически можно тремя способами:
1) через покрытие кода (мечты, мечты...)
class X;
void foo(X* x) {
bar(x);
#pragma TURN CONST ON
buz(x); // вот здесь - и далее вглубь - константность навешана на всё#pragma TURN CONST OFF
bar(x);
buz(x);
}
компилятор должен провалиться в bar() и неявно навесить там константность
2) через типы — например, на шаблонах (фактически, это то же покрытие кода) — гору кода переписать, либо выбрать другой язык (скалу)
3) через, внезапно, рантаймовые проверки.
Просто натыкать флажков и ассертов
class X {
#ifdef _DEBUG
bool is_mutable = true;
thread_local static bool all_mutable = true;
void turn_mutable(bool m) { is_mutable = m; }
static void turn_all_mutable(bool m) { all_mutable = m; }
void assert_mutable() { assert(is_mutable && all_mutable); }
#else
void turn_mutable(bool m) {}
static void turn_all_mutable(bool m) {}
void assert_mutable() {}
#endif
.....
};
void foo(X* x) {
bar(x);
X::turn_all_mutable(false);
buz(x);
X::turn_all_mutable(true);
bar(x);
buz(x);
}
Я нарочно не вдаюсь в нюансы — понятно, что тут логика скорее не двоичная, а счётчика вложенных запретов. И под это дело можно и RAII присобачить, и делать это нужно будет грамотно...
Перекуём баги на фичи!
Re: "class const - метод" - можно ли организовать?
Здравствуйте, _hum_, Вы писали:
__>самый главный недостаток динамического проверки, что ошибки ловятся уже в процессе работы, а значит, прерывают нормальное течение программы. к тому же не все их можно самому предугадать и словить. вот потому-то и стараются как можно больше проверок возложить на компилятор.
Тут я согласен.
__>погодите-погодите, кто говорил, что речь идет о динамическом связывании? во многих случаях (в том числе в моем) можно обойтись и статическим (никаких виртуальных функций, никаких observer-pattern, — обычная "магия шаблонов". см., например, библиотеку boost). но от этого проблема не пропадает (что указывает на ее общий характер).
Да, речь идёт о динамическом связывании, так как вы говорите об архитектуре сигнал-слот. Архитектура сигнал-слот сводится к динамическому созданию списков функций — других реализаций я не видел. (Я, кстати, и не уверен, что в принципе можно создать статический вариант этой архитектуры без использования шаблонных виртуальных методов, которых в С++ нет)
__>принципиальное отличие — вы можете и сами это проконтролировать (например, проверкой выполнения условия возможности удаления или использовать RAII). а вот отследить скрытые циклические зависимости, как в моем примере — это уже во многом неподъемная для программиста задача. потому и должен в этом случае приходить на помощь компилятор.
Я не вижу разницы. Нет никакой проблемы в том, чтобы узнать во время выполнения, что данная функция вызвана из самой себя через последовательность других функций.
И каждый день — без права на ошибку...
Re[8]: "class const - метод" - можно ли организовать?
Здравствуйте, B0FEE664, Вы писали:
BFE>Здравствуйте, _hum_, Вы писали:
__>>погодите-погодите, кто говорил, что речь идет о динамическом связывании? во многих случаях (в том числе в моем) можно обойтись и статическим (никаких виртуальных функций, никаких observer-pattern, — обычная "магия шаблонов". см., например, библиотеку boost). но от этого проблема не пропадает (что указывает на ее общий характер).
BFE>Да, речь идёт о динамическом связывании, так как вы говорите об архитектуре сигнал-слот. Архитектура сигнал-слот сводится к динамическому созданию списков функций — других реализаций я не видел. (Я, кстати, и не уверен, что в принципе можно создать статический вариант этой архитектуры без использования шаблонных виртуальных методов, которых в С++ нет)
возможно, дело в терминологии. я говорю лишь, что есть реализации сигнал-слот без использования виртуальных функций (просто используются более продвинутые варианты call back-функций, позволяющие на этапе компиляции отслеживать корректность (по типам) вызовов и писать код безо всяких понижающих приведений типов).
__>>принципиальное отличие — вы можете и сами это проконтролировать (например, проверкой выполнения условия возможности удаления или использовать RAII). а вот отследить скрытые циклические зависимости, как в моем примере — это уже во многом неподъемная для программиста задача. потому и должен в этом случае приходить на помощь компилятор.
BFE>Я не вижу разницы. Нет никакой проблемы в том, чтобы узнать во время выполнения, что данная функция вызвана из самой себя через последовательность других функций.
вот здесь хотелось бы поподробнее (у вас 1000 разных функций, которые друг друга вызывают, и нужно определить, есть ли вариант зацикливания).
Re[8]: "class const - метод" - можно ли организовать?
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, _hum_, Вы писали:
__>>Потому встал вопрос, есть ли в других языках или в новом стандарте с++ что-нибудь наподобие "class const — метода", который делает константными ЛЮБЫЕ this данного класса в своей области видимости, и тем самым предотвращает всякое изменение любого (а значит и заданного)объекта данного класса?
К>Навесить константность на все объекты теоретически можно тремя способами:
К>1) через покрытие кода (мечты, мечты...) К>
К>class X;
К>void foo(X* x) {
К> bar(x);
К> #pragma TURN CONST ON
К> buz(x); // вот здесь - и далее вглубь - константность навешана на всё
К> #pragma TURN CONST OFF
К> bar(x);
К> buz(x);
К>}
К>
К>компилятор должен провалиться в bar() и неявно навесить там константность
К>2) через типы — например, на шаблонах (фактически, это то же покрытие кода) — гору кода переписать, либо выбрать другой язык (скалу) К>
К>Я нарочно не вдаюсь в нюансы — понятно, что тут логика скорее не двоичная, а счётчика вложенных запретов. И под это дело можно и RAII присобачить, и делать это нужно будет грамотно...
да, 1) — наверное как раз то, что нужно было бы — обобщение подхода с const-спецификаторами.
2) — немного запутанный и, как мне показалось, все-таки не решающий проблемы с косвенными изменениями (как в исходном моем примере)
3) — это не подходит (уже обсуждалось ранее).