Пытаюсь компилировать код, отлаженный под компиляторами MS VC++ 15.xx, компиляторами из новых студий (19.xx). В коде есть несколько классов, содержащих volatile-переменные. На них выдаются предупреждения:
warning C5220: 'Class::Var': a non-static data member with a volatile qualified type no longer implies that compiler generated copy/move constructors and copy/move assignment operators are not trivial... to simplify migration, consider the temporary use of /Wv:18 flag with the version of the compiler with which you used to build without warnings
Этим классам вообще не нужны ни конструкторы копирования/перемещения, ни операторы присваивания. Объявил фиктивные конструктор и оператор присваивания, как я это всегда делал для классов с const-членами — не помогло.
От этого можно как-то избавиться, кроме как принудительно запретить эти предупреждения? Вообще, что за "нетривиальность" оно имеет в виду?
В плане доступа/синхронизации с этими переменными все корректно, я просто хочу быть уверен, что компилятор нигде не сунет переменную в регистр, и не уберет операции чтения из памяти.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Пытаюсь компилировать код, отлаженный под компиляторами MS VC++ 15.xx, компиляторами из новых студий (19.xx). В коде есть несколько классов, содержащих volatile-переменные.
Самое главное — не приводи минимальный код для воспроизведения, а то быстро ответят
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>А смысл в таком коде? Тот, кто не знает про конкретно это предупреждение, по коду сможет сделать только предположения, а это я и сам могу.
Я не о том, что конструктор/оператор, сгенерированный компилятором, будет считаться нетривиальным, а о том, что компилятор мог бы там в действительности сгенерить, чтобы оправдать это. Традиционно он генерит пустой конструктор, и оператор присваивания, побайтно копирующий объект. Что "нетривиального" он мог бы сам сгенерить для класса, содержащего volatile-переменную?
Или речь лишь о том, чтобы не допустить копирования/перемещения таких объектов, кроме как через явно определенные в классе средства? Если так, то каким образом запретить это явно, кроме добавления "=delete"? Мне нужно, чтоб код соответствовал и стандарту C++03, не хотелось бы городить там лишних условностей.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Или речь лишь о том, чтобы не допустить копирования/перемещения таких объектов, кроме как через явно определенные в классе средства? Если так, то каким образом запретить это явно, кроме добавления "=delete"? Мне нужно, чтоб код соответствовал и стандарту C++03, не хотелось бы городить там лишних условностей.
Можно явно указать стандарт в параметрах сборки. А если хотите код, который поддерживается не только С++03, то извольте городить макросы для условной компиляции. В бусте такого добра хватает.
Здравствуйте, SaZ, Вы писали:
SaZ>Можно явно указать стандарт в параметрах сборки.
Я б с радостью, но VC++ не умеет ниже C++14.
SaZ>А если хотите код, который поддерживается не только С++03, то извольте городить макросы для условной компиляции.
Мне пока более всего интересно, в чем может заключаться фактическая нетривиальность конструктора и/или оператора присваивания, которые мог бы сгенерить компилятор по новому стандарту. Вы об этом что-нибудь знаете?
ЕМ>warning C5220: 'Class::Var': a non-static data member with a volatile qualified type no longer implies that compiler generated copy/move constructors and copy/move assignment operators are not trivial... to simplify migration, consider the temporary use of /Wv:18 flag with the version of the compiler with which you used to build without warnings
ЕМ>В коде есть несколько классов, содержащих volatile-переменные. На них выдаются предупреждения:
Если не секрет, зачем понадобились volatile-переменные? Какое-то устройство "замаплено" в память и нужно чтобы компилятор не с оптимизировал обращения к этой памяти?
Здравствуйте, Максим, Вы писали:
М>зачем понадобились volatile-переменные?
Для реализации некоторых легковесных методов синхронизации. Например, там, где циклически выполняется группа операций, и этот цикл нужно останавливать по внешнему сигналу. Использовать там средства ОС избыточно — по уши хватит и volatile-переменных.
ЕМ>Для реализации некоторых легковесных методов синхронизации. Например, там, где циклически выполняется группа операций, и этот цикл нужно останавливать по внешнему сигналу. Использовать там средства ОС избыточно — по уши хватит и volatile-переменных.
Мне кажется, Евгений, что так делать не стоит, volatile не гарантирует синхронизацию общих данных. Лучше использовать гарантированно lock-free на любых платформах std::atomic_flag. https://en.cppreference.com/w/cpp/atomic/atomic_flag
ранее выяснили что он знает только c++98
атомики сильно сложно будет для него
к тому же он хочет обратной совместимости для c++98
что бы и для win3.11 можно было сбилдить
и продать исходники клиенту из прошлого, который на машине времени переместится в настоящее
Здравствуйте, Максим, Вы писали:
М>Мне кажется, Евгений, что так делать не стоит, volatile не гарантирует синхронизацию общих данных.
volatile должно гарантировать отсутствие буферизации, добавляемой компилятором. Если я, в свою очередь, гарантирую запись изменений в память параллельным потоком, то что может помешать считыванию измененных значений?
М>Лучше использовать гарантированно lock-free на любых платформах std::atomic_flag
Мне пока не актуальны платформы, отличные от x86/x64, даже ARM под большим вопросом. Ну и не люблю я библиотечных конструкций в ядерном коде — они то реализованы "с особенностями", то тянут за собой лишний код из CRT, то не реализованы вообще.
ЕМ>volatile должно гарантировать отсутствие буферизации, добавляемой компилятором. Если я, в свою очередь, гарантирую запись изменений в память параллельным потоком, то что может помешать считыванию измененных значений?
Volatile accesses cannot be optimized out or reordered ... This makes volatile objects suitable for communication with a signal handler, but not with another thread of execution, see std::memory_order.
Другими словами, можно ожидать, что компилятор просто так не выкинет volatile объекты, но нельзя расчитывать, что значения какой-то конкретной пременной в коде (например флага, котрый используется для остановки цикла) будут одинаковы для разных CPU.
Вот, кстати, неплохая статья с описанием того, где может пригодиться volatile https://habr.com/ru/company/abbyy/blog/161607/
ЕМ>Ну и не люблю я библиотечных конструкций в ядерном коде — они то реализованы "с особенностями", то тянут за собой лишний код из CRT, то не реализованы вообще.
Вы в ядре программируете? Там ведь свой набор примитивов синхронизации.
вы что вчера на форуме ?
Евгению все равно на ваши советы
он будет находить любые доводы почему ему это не подходит
просто ему во франции скучно,а из окружения только жена и дети
вот он и находит такую отдушину на форуме
для "поговорить ни о чем", но типа "на тему программирования"
Здравствуйте, Максим, Вы писали:
М>Другими словами, можно ожидать, что компилятор просто так не выкинет volatile объекты, но нельзя расчитывать, что значения какой-то конкретной пременной в коде (например флага, котрый используется для остановки цикла) будут одинаковы для разных cpu.
Эти рассуждения годятся для программирования на C++ в стиле каких-нибудь Python или JS, где программа имеет дело с абстрактной виртуальной средой. Я программирую не для сферического железа в вакууме, в расчете на гипотетические платформы, а для вполне конкретного. Поэтому мне интересно, в каких конкретно случаях "нельзя рассчитывать", и почему. Вам известны такие сценарии?
М>Вы в ядре программируете? Там ведь свой набор примитивов синхронизации.
Не вижу смысла дергать примитивы, когда можно обойтись без них.
Ну так да. Самый простой сценарий. Есть пременная flag которая в одном потоке читается, что-то в духе
while(flag) {...}
а во втором изменяется
flag = false
Так вот, изменяя переменную во втором потоке, мы не знаем когда эти изменения "прилетят" в первый поток. Все зависит от того, где находится эта самая переменная, когда будут сброшены процессорные кеши итд.