есть код: Код (C++): struct T { void *payload[128]; ~T(){} T(){} // T(T const&){} }; void pass_arg(T arg0) { arg0.payload[0]=(void*)64; } void foo() { pass_arg(T()); } сравнивал gcc, clang, icc, msc (все последних версий, что доступны на godbolt, без оптимизаций итд); у всех всё адекватно, кроме msc, как всегда: 1) stack_alloc sizeof T (foo) 2) CTOR (foo) 3) pass_arg(addrof stack_alloc);...(pass_arg code) ...;ret; 4) DTOR (foo) 5) stack_dealloc (foo) у первых троих всё вроде норм и одинаково: вызывающий выделяет стековую память, вызывает конструктор на выделенной памяти, передаёт поинтером указатель в pass_arg, там выполняется код, возврат, опять же - вызывающий вызывает деструктор и затем деаллокация. у msc же откудато берётся дублирующий обьект, какбудто это copy-initialization from value, и соответственно ситуация исполняется в таком порядке: выделение памяти sizeof T * 2, конструктор, копия памяти, обработанной конструктором, во второй блок (по сути - вызов конструктора для 2го обьекта) - передача в test_arg также указателем. перед выходом из test_arg - деструктор вот этого темпового, что неявно проинициализировался просто копией, возврат в foo, и деструктор соответсна исходного. так вот - откуда у msc второй обьект взялся? ключи на всяк /std:c++17 /Od /EHs-c- /Ob0 /Oy- /GS- /GR- -std=c++17 -O0 -m32 -fno-rtti -fno-exceptions -fno-stack-protector ***ПС: если копирующий конструктор раскомментить, то дополнительного объекта msc не создаёт.
дадада, именно о copyelision я и замутил тему. с 17 стандарта вроде как - это изменения в ядре в принципе
Похоже, MSVC считает, что если конструктор копирования тривиален, то можно копировать объект сколько угодно и вызывать деструктор только 1 раз, даже если деструктор не тривиален. Но это, конечно, баг. Стандарт даёт право копировать объекты несмотря на т.н. обязательное copy elision если тривиальны конструкторы копирования, перемещения и деструктор https://timsong-cpp.github.io/cppwp/n4659/class.temporary#3
msc вообще последнее время создаёт впечатление о своей команде разработчиков, самое яркое что помню - это невызов конструктора базового класса через brace-init-list в constructor-member-initializers-list, я тогда(год назад) отрепортил, так мне сказали что я гражданин и ничего не смыслю, а затем - что да мы в курсе этой проблемы, пофиксим, но вы всё равно - *** и с этого момента обнова вышла аж через 2 месяца.