-1

我试图使用构造函数在静态函数中创建一个对象。这是代码

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)由于对象地址在销毁它之前具有先前的值并返回调用返回存储它的变量的地址。当我尝试访问它时,我能够这样做,因为该内存地址仍然存在。

4

1 回答 1

1

这不是你制作单身人士的方式。该声明

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++ 只允许将临时绑定到 const 引用。有办法解决这个问题,但这无关紧要。该程序的输出可能会有所不同,具体取决于编译器和优化级别。例如没有优化的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
于 2018-05-26T11:02:24.740 回答