Это не так, как вы делаете синглтон.Оператор
A();
создает временный объект класса A, который уничтожается (согласно стандарту) в конце инструкции.
Действительно, память выделяется перед вызовом конструктора.Результирующий объект может быть назначен или передан по ссылке или значению любой функции этого оператора, но в первом случае ссылка действительна только до конца выражения вызова.Исключением является то, что если он был назначен для ссылки, его продолжительность жизни увеличивается до одной ссылки.После окончания срока службы объекта любой доступ к памяти, которую он использовал, приводит к UB, при условии, что он может использоваться любыми другими операциями.
Любой доступ к объекту после вызова деструктора также является UB.Вот пример (этот код намеренно содержит UB)
#include <iostream>
class A {
public:
A() { this->a = 50; std::cout << "constructor called... " << this << std::endl; }
~A() { this->a = 10; std::cout << "destructor called... " << this << std::endl; }
int a;
static const A &create() {
const A& addr = A();
std::cout << "a = " << addr.a << std::endl;
return addr;
}
};
int main() {
const A &ref = A::create();
std::cout << "a = " << ref.a << std::endl;
return 0;
}
Обратите внимание, что C ++ позволяет привязывать временные данные только к константной ссылке.Есть способ обойти это, но это не имеет значения.Вывод этой программы может варьироваться в зависимости от компилятора и уровня оптимизации.Например, clang без оптимизации:
constructor called... 0x7ffc1f7991d0
a = 50
destructor called... 0x7ffc1f7991d0
a = 4202884
gcc может выдать 10 в последней строке.MS может зависнуть на нем.Ключевое слово «может», нет правил, которые бы управляли тем, что случилось бы.Объект перестал существовать после того, как create()
вернул ссылку на него, потому что срок жизни addr
подошел к концу, и у нас осталась висячая ссылка.
Очевидно, что мы можем продлить срок службы addr
, сделав его статическим.
static const A &create() {
static const A& addr = A();
std::cout << "a = " << addr.a << std::endl;
return addr;
}
Статическая переменная в области видимости функции будет создана при первом вызове функции и прекратит существование при остановке процесса.
constructor called... 0x6031b8
a = 50
a = 50
destructor called... 0x6031b8