在这种情况下显式调用std :: cout时如何改变析构函数的行为?

时间:2018-10-20 19:07:34

标签: c++ oop printf destructor cout

我正在尝试显式调用对象的析构函数。以下代码按预期工作:

class Foo {
    public:

    ~Foo() {
        x_=x_+10;
        std::cout << "x_ = " << x_ << std::endl;
    }

    int x() {
        return x_;
    }
    int x_=0;
};


int main()
{
    Foo f;
    std::cout << "f.x() = " << f.x() << std::endl;

    f.~Foo();
    f.~Foo();

    std::cout << "f.x() = " << f.x() << std::endl;
    return 0;
}

打印输出为:

f.x() = 0                                                                                                                                                      
x_ = 10                                                                                                                                                        
x_ = 20                                                                                                                                                        
f.x() = 20                                                                                                                                                     
x_ = 30

正如预期的那样,每次调用析构函数时,x_都会增加10,因此我们看到从10扩展到20到30的过程。

但是,如果我们从析构函数中删除std::cout,例如:

class Foo {
    public:

    ~Foo() {
        x_=x_+10;
    }

    int x() {
        return x_;
    }
    int x_=0;
};


int main()
{
    Foo f;
    std::cout << "f.x() = " << f.x() << std::endl;

    f.~Foo();
    f.~Foo();

    std::cout << "f.x() = " << f.x() << std::endl;
    return 0;
}

然后打印输出变为:

f.x() = 0                                                                                                                                                      
f.x() = 0 

析构函数中的增量不再起作用。有人可以解释为什么打印语句会影响析构函数的行为吗?

3 个答案:

答案 0 :(得分:0)

f.~Foo();
f.~Foo();

不要。只是不要。这是不好的。很坏。绝对不要这样做,尤其是当您不了解析构函数是什么时。

编译器只是跳过代码,因为这是未知领域,在这种情况下它会做任何想做的事情。

Explicit destructor call is not working

答案 1 :(得分:0)

使用损坏的对象是未定义的行为。因此,在析构函数结束后,将无法观察到对析构函数中对象stste的任何更改。

当您将析构函数增加10 ina时,编译器可以轻松证明这是不可观察的,因此无需在运行时浪费时间。

随后打印时,它可以复制值,加10,然后打印副本。但是编译器改为将其递增并打印。

在C ++标准下,具有未定义行为的程序在未定义行为之前和之后的行为均不受限制。

答案 2 :(得分:0)

{
    Foo f;
    f.~Foo();
}

这是未定义的行为。 f是具有自动存储持续时间的变量。这意味着它的生命周期是自动管理的,您不能明确地终止它的生命。

具有未定义行为的程序可以以任何方式运行,因此您不能依靠观察到的UB程序所做的任何事情。