Стандарт явно разрешает (а в C++17 — даже требует) компилятору устранять временные объекты (а также, в меньшей степени, именованные) путём конструирования объектов непосредственно в конечной точке цепи копирований/перемещений. en.cppreference.com/w/cpp/language/copy_elision
Не асинхронный, а буферизованный. flush дёргается при завершении программы из деструктора глобального объекта класса std::ios_base::Init: en.cppreference.com/w/cpp/io/ios_base/Init
У меня в Федоре 1123 строки получается. (std::endl, в отличие от просто '\n', если что, делает flush — может быть вы его написали?)
Верно. Правда, учитывая количество любителей занулять структуры memset-ом (и соображения совместимости C++ с C) и просто неудобство подхода, на практике разработчики компиляторов на такое никогда не пойдут)
В любом случае преобразование адреса функции к bool гарантированно возвращает true, так как оно опирается именно на null pointer value.
Что нарушает соглашение что 0 это не валидный указатель
Это требование Стандарта, а не просто «соглашение».
A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of object pointer or function pointer type.
A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of pointer to object or pointer to function type.
В C++17 fold-expression с операцией следования позволяет без рекурсии совершить произвольное действие над всеми элементами parameter pack-а.
Простой (но плохой) пример:
Мне пригодилась в игрушечном проекте при расчёте вклада отдельной наблюдаемой (зависящей от известного на этапе компиляции числа модельных переменных, разного для наблюдаемых разных видов) в общий градиент ошибки — выглядело это так:
Опциональная поддержка GC (как я понимаю, без возможности вызова деструкторов) появилась ещё в C++11 (safely-derived pointers, std::declare_reachable и т. п.).
В шаблонах даже без функций есть неоднозначности между объявлениями и выражениями — как, например, в случае a::b * c или a::b<c> d, где a — параметр шаблона.
Сломается обратная совместимость, ибо new T^(...) — валидная конструкция с вполне определённым смыслом:
struct T{};
T *operator^(T *lhs, T)
{
return lhs;
}
int main()
{
T x;
T *ptr = new T^(x);
}
Синтаксис C++ и так перегружен по части всевозможного использования закорючек — в стандарте в некоторых случаях приходится явно разрешать неоднозначность интерпретации тех или иных конструкций (например, является ли T() типом функции, возвращающей значение типа T, или созданием временного объекта типа T).
К вашему вопросу «Когда это у нас std::string стал mt-safe?».
и спащена цитата ниже?
Цитата из стандарта C++.
«Если вы используете потоки в реализации — вы должны сами обеспечивать их безопасность», но из этого никак не следует то, что строка mt-safe.
Неверно. Перевожу на русский, раз такие трудности:
«Реализации могут расшаривать их собственные внутренние объекты между потоками, если эти объекты невидимы для пользователей и защищены от гонок.»
«Реализация» — это компилятор+стандартная библиотека, если что. В частности, реализация std::string.
Потокобезопасность std::string (в том смысле, что два потока могут параллельно работать с двумя разными объектами std::string, пусть даже полученными из одного объекта std::string присваиванием или конструктором копии) следует из всей совокупности требований раздела «Data race avoidance», в частности:
A C++ standard library function shall not directly or indirectly access objects (1.10) accessible by threads other than the current thread unless the objects are accessed directly or indirectly via the function’s arguments, including this.
A C++ standard library function shall not directly or indirectly modify objects (1.10) accessible by threads other than the current thread unless the objects are accessed directly or indirectly via the function’s non-const arguments, including this.
В рамках статьи говорилось о велосипедах, вот и говорите о них.
Я отвечаю на ваш комментарий про якобы потоконебезопасный std::string, а не на статью.
Вы написали два вопроса про std::string и один — про COW-строки, таким образом, словно это три вопроса на одну и ту же тему.
С тех самых пор, как появились потоки и само понятие потокобезопасности, как следствие — то есть с C++11. Все классы потокобезопасны (на базовом уровне), если не оговорено обратное; в частности, здесь применимо следующее правило:
Implementations may share their own internal objects between threads if the objects are not visible to users and are protected against data races.
(С++11/14, 17.6.5.9 Data race avoidance, абзац 7
C++17, 20.5.5.9 Data race avoidance, абзац 7)
На каком основании вы требуете mt-safe от COW-строки
В C++ нет понятия «COW-строка», есть просто «строка». COW — это один из возможных видов реализации, про которые пользователь ничего знать не обязан, ибо инкапсуляцию никто не отменял. Связанные с COW проблемы потокобезопасности лежат исключительно на разработчиках стандартной библиотеки.
При этом компилятор даже не поверит вам, если вы везде напишите const, потому что он не оптимизирует, основываясь на const. Если вы где-то написали const, компилятор проигнорирует это, потому что где-то в другом месте вы могли написать const_cast.
Оптимизирует. Пример (присваивание *ptr = 9; может изменить x2, но не x1): godbolt.org/g/QPvwup С массивами получается аналогично.
Модификация константного объекта (посредством const_cast или другими путями) — неопределённое поведение, компилятор всегда имеет право полагать, что такого не происходит.
Другое дело, если нам передали параметр типа const T& или const T* и он ссылается на на самом деле неконстантный объект.
for(i = 0; i < nrows; i++){
free(array[i]);
}
free(array);
1) Исправьте int на double.
2) Не в C/C++, а в C. В C++ для этого есть vector, а начиная с C++14 — dynarray (в частности, не нужно явное освобождение — в C++ автоматическое управление ресурсами). А в C99 есть variable length arrays, вообще идеально решающие эту задачу (правда, в C11 ставший опциональным, и с C++ они несовместимы).
3) Это явно не самый лучший способ выделить память под двумерный массив. Лучше выделить единым блоком — и выделение/освобождение проще, и работа будет эффективнее за счёт большей локальности данных и меньшей косвенности в обращении (правда, индексировать его будет сложнее).
Хотя не являющиеся программистами люди действительно так и будут писать.
Проблема в том, что const real отличается от простого real. Если функция, принимающая real, получит const real, она вернёт ошибку.
???
int f(double x);
int fc(const double x);
...
double y = 5;
const double yc = 9;
f(y); //OK
fc(y); //OK
f(yc); //OK
fc(yc); //OK
Может, имелась в виду какая-нибудь передача по указателю, для которого забыли написать const? (T* к const T* прекрасно преобразуется, если что.)
C – язык сравнительно примитивный, поэтому физики, избирающие себе C/C++, занимаются объектно-ориентированным программированием.
Это предложение сломало мне мозг. Имелось в виду, что физики, выбирающие C/C++, в силу примитивности C смотрят в сторону C++, а он объектно-ориентированный? И жалуются потом, что им сложно? И поэтому надо выбирать фортран?
Странная логика. Тем более что ООП — просто парадигма. Можно и на C++ писать в процедурном стиле (и не углубляться в изучение языковых средств поддержки ООП), а можно и на фортране мутить ООП, если очень надо.
Объекты – очень громоздкие структуры по сравнению со структурами данных, предпочитаемыми физиками: массивами.
В C++ классы могут быть неполиморфными, в силу чего их объекты физически будут представлять собой просто записи из полей (подобно derived type в том же самом фортране).
Объекты и массивы сравнивать бессмысленно, они разные задачи решают. Но даже если совсем забить на инкапсуляцию и вообще философию ООП, то «объекты» и «массивы» — это разные способы построения одних типов данных из других, они друг с другом не конкурируют. Массив — большое или неопределённое количество однородных элементов, объект — определённый набор разных по типу и/или смыслу элементов (лишь с учётом вышесказанного; на самом деле, разумеется, эта некая целостная сущность предметной области, а не агрегат для данных).
Если бы мы передавали его по ссылке, переданные данные не располагались бы в памяти подряд.
И как вы себе представляете в Си передачу по ссылке подмассива, элементы которого расположены неподряд?
Если первый индекс — индекс молекулы, то координаты одной молекулы будут располагаться подряд. В противном случае программисту на Си придётся вручную сформировать временный массив. Если только он явно не сделал одним из передаваемых параметров шаг (наряду с указателем на первый элемент и размером), специально для таких случаев.
В цивилизованном мире UTF-8 — кодировка по умолчанию. Так что если вы сохранили исходник в UTF-8, то и результирующая строка в норме должна быть в UTF-8, даже в отсутствие префикса u8 (как минимум, у меня под линуксом в gcc дела обстоят именно так). Это не требуется стандартом (source character set и execution character set, в принципе, могут быть разными), но и не противоречит ему.
Чтобы (достоверно) увидеть ошибку выхода за границы массива в вашем примере, надо знать компилятор и кодировку исходника. Без этой информации отсутствие выхода за границы более вероятно.
en.cppreference.com/w/cpp/language/copy_elision
У меня в Федоре 1123 строки получается. (std::endl, в отличие от просто '\n', если что, делает flush — может быть вы его написали?)
В любом случае преобразование адреса функции к bool гарантированно возвращает true, так как оно опирается именно на null pointer value.
Это требование Стандарта, а не просто «соглашение».
(C++17 7.11 Pointer conversions [conv.ptr];
C++11/14 4.10 Pointer conversions [conv.ptr])
(C++98/03 4.10 Pointer conversions [conv.ptr])
Простой (но плохой) пример:
Мне пригодилась в игрушечном проекте при расчёте вклада отдельной наблюдаемой (зависящей от известного на этапе компиляции числа модельных переменных, разного для наблюдаемых разных видов) в общий градиент ошибки — выглядело это так:
Здесь ArgsIndexes — параметр шаблона, объявлен как
Синтаксис C++ и так перегружен по части всевозможного использования закорючек — в стандарте в некоторых случаях приходится явно разрешать неоднозначность интерпретации тех или иных конструкций (например, является ли T() типом функции, возвращающей значение типа T, или созданием временного объекта типа T).
К вашему вопросу «Когда это у нас std::string стал mt-safe?».
Цитата из стандарта C++.
Неверно. Перевожу на русский, раз такие трудности:
«Реализации могут расшаривать их собственные внутренние объекты между потоками, если эти объекты невидимы для пользователей и защищены от гонок.»
«Реализация» — это компилятор+стандартная библиотека, если что. В частности, реализация std::string.
Потокобезопасность std::string (в том смысле, что два потока могут параллельно работать с двумя разными объектами std::string, пусть даже полученными из одного объекта std::string присваиванием или конструктором копии) следует из всей совокупности требований раздела «Data race avoidance», в частности:
Я отвечаю на ваш комментарий про якобы потоконебезопасный std::string, а не на статью.
Вы написали два вопроса про std::string и один — про COW-строки, таким образом, словно это три вопроса на одну и ту же тему.
С тех самых пор, как появились потоки и само понятие потокобезопасности, как следствие — то есть с C++11. Все классы потокобезопасны (на базовом уровне), если не оговорено обратное; в частности, здесь применимо следующее правило:
(С++11/14, 17.6.5.9 Data race avoidance, абзац 7
C++17, 20.5.5.9 Data race avoidance, абзац 7)
В C++ нет понятия «COW-строка», есть просто «строка». COW — это один из возможных видов реализации, про которые пользователь ничего знать не обязан, ибо инкапсуляцию никто не отменял. Связанные с COW проблемы потокобезопасности лежат исключительно на разработчиках стандартной библиотеки.
Если -fstrict-aliasing что-то «испортил», код в любом случае надо переписывать. К тому же, он включается по умолчанию уже на -O2.
Оптимизирует. Пример (присваивание *ptr = 9; может изменить x2, но не x1): godbolt.org/g/QPvwup С массивами получается аналогично.
Модификация константного объекта (посредством const_cast или другими путями) — неопределённое поведение, компилятор всегда имеет право полагать, что такого не происходит.
Другое дело, если нам передали параметр типа const T& или const T* и он ссылается на на самом деле неконстантный объект.
1) Исправьте int на double.
2) Не в C/C++, а в C. В C++ для этого есть vector, а начиная с C++14 — dynarray (в частности, не нужно явное освобождение — в C++ автоматическое управление ресурсами). А в C99 есть variable length arrays, вообще идеально решающие эту задачу (правда, в C11 ставший опциональным, и с C++ они несовместимы).
3) Это явно не самый лучший способ выделить память под двумерный массив. Лучше выделить единым блоком — и выделение/освобождение проще, и работа будет эффективнее за счёт большей локальности данных и меньшей косвенности в обращении (правда, индексировать его будет сложнее).
Хотя не являющиеся программистами люди действительно так и будут писать.
???
Может, имелась в виду какая-нибудь передача по указателю, для которого забыли написать const? (T* к const T* прекрасно преобразуется, если что.)
Это предложение сломало мне мозг. Имелось в виду, что физики, выбирающие C/C++, в силу примитивности C смотрят в сторону C++, а он объектно-ориентированный? И жалуются потом, что им сложно? И поэтому надо выбирать фортран?
Странная логика. Тем более что ООП — просто парадигма. Можно и на C++ писать в процедурном стиле (и не углубляться в изучение языковых средств поддержки ООП), а можно и на фортране мутить ООП, если очень надо.
В C++ классы могут быть неполиморфными, в силу чего их объекты физически будут представлять собой просто записи из полей (подобно derived type в том же самом фортране).
Объекты и массивы сравнивать бессмысленно, они разные задачи решают. Но даже если совсем забить на инкапсуляцию и вообще философию ООП, то «объекты» и «массивы» — это разные способы построения одних типов данных из других, они друг с другом не конкурируют. Массив — большое или неопределённое количество однородных элементов, объект — определённый набор разных по типу и/или смыслу элементов (лишь с учётом вышесказанного; на самом деле, разумеется, эта некая целостная сущность предметной области, а не агрегат для данных).
И как вы себе представляете в Си передачу по ссылке подмассива, элементы которого расположены неподряд?
Если первый индекс — индекс молекулы, то координаты одной молекулы будут располагаться подряд. В противном случае программисту на Си придётся вручную сформировать временный массив. Если только он явно не сделал одним из передаваемых параметров шаг (наряду с указателем на первый элемент и размером), специально для таких случаев.
Он может быть в ASCII-совместимой кодировке — например, в UTF-8 (весьма вероятно, если вы под Linux-ом) или Windows-1251 (если вы под виндой).
Чтобы (достоверно) увидеть ошибку выхода за границы массива в вашем примере, надо знать компилятор и кодировку исходника. Без этой информации отсутствие выхода за границы более вероятно.