Попытка создать объект с помощью конструктора внутри статической функции в C ++ - PullRequest
0 голосов
/ 26 мая 2018

Я пытался создать объект внутри статической функции, используя конструктор.Вот код

class A {
public:
    A() { this->a = 50; std::cout << "constructor called... " << this << std::endl; setAddr(this); }
    ~A() { this->a = 10;  std::cout << "destructor called... " << this << std::endl; }
    int a;
    static A* addr;
    static void setAddr(A* ad) { addr = ad; }
    static A &create() { A(); return *addr; }
};

A* A::addr = NULL;

int main() {
    A &ptr = A::create();
    std::cout << "a = " << ptr.a << std::endl;
    ptr.a = 100;
    std::cout << "a = " << ptr.a << std::endl;
    getch();
    return 0;
}

Я знаю, что использование new - лучший способ сделать это, но я пытался сделать это, используя contructor, чтобы узнать, можно ли это сделать или нет.

вывод был:

конструктор с именем ... 009AF874

деструктор с именем ... 009AF874

a =10

a = 100

Теперь вот мой вопрос,

1), почему деструктор вызывается, когда не создается объект с использованиемлюбое объявление типа A obj;

2) и если вызывается деструктор, то как я могу присвоить значение для otr.a;

Просматривая вывод программы, я сделал следующеезаключение.

1) Я где-то читал, что конструктор вызывается после выделения памяти для объекта.И если объект создан, то он должен быть уничтожен, и область действия объекта obj решила уничтожить его сейчас.

2) Так как адрес объекта имеет предыдущие значения, прежде чем уничтожить его и возвращает вызов, возвращаем адрес переменнойхранить его.Когда я попытался получить к нему доступ, я смог это сделать, поскольку этот адрес памяти все еще существует.

1 Ответ

0 голосов
/ 26 мая 2018

Это не так, как вы делаете синглтон.Оператор

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
...