Ответ 1
Во-первых: что такое объект?
[intro.object]\1
[...] Объект - это область хранения [...]
Хранилище выделяется до истечения времени жизни объекта:
[basic.life]
До начала жизни объекта, но после хранения который будет занимать объект, было выделено [..] любым указателем, который относится к месту хранения, где объект будет или находился могут использоваться, но только ограниченным образом. По строительству или разрушению объекта см. 12.7 [строительство и уничтожение]. В противном случае, такой указатель относится к выделенному хранилищу (3.7.4.2) и использует указатель, как если бы указатель имел тип void *, хорошо определен.
Таким образом, указатель ссылается на выделенное пространство, и нет никакого вреда в его использовании. Вы просто запрашиваете адрес стека, и любой компилятор должен иметь возможность правильно разобраться. В этом конкретном экземпляре не требуется операция инициализации самим объектом.
Это имеет смысл, поскольку в классическом компиляторе AST-моды, если вы посмотрите стандартную иерархию деклараторов, в простой игрушечный код, например
class command {
public:
command(int) {
}
};
int funct(command*) {
return 2;
}
int main() {
command com(funct(&com));
}
строка
command com(funct(&com));
интерпретируется следующим образом:
[dcl.decl]
simple-declaration:
attribute-specifier-seqopt decl-specifier-seqopt init-declarator-listopt;
...
initializer:
brace-or-equal-initializer
( expression-list ) // The declaration statement is already specified
И, наконец, для вашего кода это то, как gcc компилирует эту строку (-O0)
command com(std::bind(test_action, &com));
->
movq %rax, -104(%rbp)
leaq -104(%rbp), %rdx
leaq -96(%rbp), %rcx
movl test_action(command*), %esi
movq %rcx, %rdi
movq %rax, -136(%rbp) # 8-byte Spill
movq %rcx, -144(%rbp) # 8-byte Spill
callq _ZSt4bindIRFvP7commandEJS1_EENSt12_Bind_helperIT_JDpT0_EE4typeEOS5_DpOS6_
leaq -80(%rbp), %rax
movq %rax, %rdi
movq -144(%rbp), %rsi # 8-byte Reload
movq %rax, -152(%rbp) # 8-byte Spill
callq _ZNSt8functionIFvvEEC1ISt5_BindIFPFvP7commandES5_EEEET_NSt9enable_ifIXntsr11is_integralISA_EE5valueENS1_8_UselessEE4typeE
movq -136(%rbp), %rdi # 8-byte Reload
movq -152(%rbp), %rsi # 8-byte Reload
callq command::command(std::function<void ()> const&)
который представляет собой просто пучок адресов стека из базового указателя, который передается функции привязки перед вызовом конструктора.
Все было бы по-другому, если бы вы на самом деле пытались использовать объект до его построения (вещи могут оказаться сложными с виртуальными таблицами функций).
Sidenote: это НЕ гарантированно будет безопасным, если вы копируете или передаете по значению объект и выходите из области видимости (и сохраняете адрес в месте расположения стека). Кроме того: если компилятор решает сохранить его (по какой-либо архитектуре/причине) в качестве смещения от базового фрейма, вы, вероятно, находитесь в undefined behaviorland.