Здравствуйте, Erop, Вы писали:
E>Но я хотел бы узнать какие так делают в реале...
Из известных компиляторов так делает clang:
пример.
E>Я вполне допускаю, что какие-то компиляторы могут делать такую нестандартную оптимизацию.
Если под нестандартностью ты понимаешь не редкость или сложность подобной оптимизации, а отсутствие её в стандарте, то это не так — явное разрешение не выделять память при вычислении new-expression в стандарте есть.
BZ>>Вообще не понимаю какая вам разница, если видимое поведение не меняется. ничто не мешает занулять v в начадле каждого цикла, например, вместо создания-уничтожения
E>Ну таки вызовы кучи -- это сайд-эффект жеж.
Всё же видимое поведение (observable behavior) и сайд-эффекты (side effects) — это немного разные вещи. В стандарте с самой первой версии было разрешено компилятору игнорировать любые сайд-эффекты, если это не влияет на видимое поведение.
До недавнего времени, правда, в стандарте была неоднозначность: с одной стороны состояние внутренней (не volatile) памяти программы не является напрямую наблюдаемым поведением, а с другой стороны в подавляющем числе реализаций операции по выделению памяти периодически приводят к взаимодействию с окружением или ОС (а формально вызов mmap, sbrk, VirtualAlloc или другой функции ОС — это уже наблюдаемое поведение, или подменённый глобальный аллокатор тоже может что-то сложное и наблюдаемое делать).
К счастью, эта неоднозначность была всё же разрешена в
n3664 в пользу первой точки зрения.
В целом правильное изменение, я считаю. Всё равно же большинство программ и программистов пользуются глобальным аллокатором как чёрным ящиком (и даже названия реализации его, зачастую, не знает). Так что тут просто узаконивается уже существующий порядок — поведение аллокатора отделяется от поведения программы — он лишь предоставляет память, а как это делается — не важно. Аналогичное положение, кстати говоря, уже давно существует для других функций, в которых семантика ставится выше реализации. Так, например, компилятор спокойно заменит вызов
memcpy(u, v, 4) на копирование 4х байт через регистр. Хотя формально программист может заменить функцию memcpy на свою, которая, например, логирует все вызовы в файл или осуществляет какие-то дополнительные проверки и действия (скажем, подобно valgrind). Но компилятор здесь руководствуется именно семантикой (memcpy копирует память) и игнорирует настоящую реализацию.