a
- это глобальный объект со статической продолжительностью хранения, поэтому он будет инициализирован в некотором предварительно выделенном хранилище за некоторое время до того, как будет выполнено тело main. Предполагая, что вызов Test не является результатом какой-то странной конструкции статического объекта, a
будет полностью построено к моменту вызова Test.
a = new A;
Это немного необычное назначение не будет (только) стандартной операцией копирования, поскольку вы назначаете указатель на A
для a, а не для объекта или ссылки. Будет ли он на самом деле компилироваться и что именно он вызывает, зависит от того, имеет ли A
оператор присваивания, который принимает указатель на A
, или что-то неявно конвертируемое из указателя на A
, или же A
имеет неявный конструктор который принимает указатель на A
(или указатель на базовый класс A
).
После редактирования, ваш код делает что-то другое!
Концептуально, он делает что-то вроде этого:
A *tmpa;
void *mem = ::operator new( sizeof(A) ); // ( or possibly A::operator new )
try
{
tmpa = new (mem) A; // placement new = default constructor call
}
catch (...)
{
::operator delete( mem );
throw;
}
a = tmpa; // pointer assignment won't throw.
Опасность написания чего-то подобного заключается в том, что вы неявно добавляете много точек последовательности, которых просто нет в оригинале, и, кроме того, компилятору разрешено генерировать код, который не выглядит так долго поскольку он ведет себя «как будто», он был написан так, насколько это может определить исполняющая программа. Это правило «как будто» применяется только к исполняющему потоку, поскольку (текущий) язык ничего не говорит о взаимодействии с другими потоками.
Для этого вам нужно использовать определенные гарантии поведения (если таковые имеются), предусмотренные вашей реализацией.