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

C++ std::cout如何更改析构函数';在这种情况下显式调用时的行为?,c++,oop,printf,destructor,cout,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::c

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

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;
}
正如预期的那样,每次调用析构函数时,x_u都会增加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;
}
析构函数中的增量不再起作用。有人能解释为什么析构函数的行为会受到print语句的影响吗

f.~Foo();
f.~Foo();
不要。别这样。这很糟糕。非常糟糕。永远不要这样做,尤其是当你不明白析构函数是什么的时候

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


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

当您在析构函数中增加10时,编译器可以很容易地证明这是不可观察的,因此无需在运行时浪费时间

当您以后打印时,它可以复制值,添加10,然后打印副本。但是编译器会在适当的位置增加并打印它

不确定行为的程序对C++的标准前后的行为没有约束,

{
    Foo f;
    f.~Foo();
}
这是未定义的行为
f
是一个具有自动存储持续时间的变量。这意味着它的生命周期是自动管理的,您不能显式地结束它的生命周期


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

这就是为什么我提到我正在进行实验,只是为了好玩。大多数情况下,显式调用析构函数是未定义的行为。您应该只有意识地使用它(例如,在高级内存分配池的上下文中)。IIRC Qt框架有一些有效的用途。显式调用析构函数的唯一合法时间是在对象分配了placement new时,因为在这种情况下,您不能使用
delete
释放对象。例如:
charbuf[sizeof(Foo)];Foo*f=new(buf)Foo;f->~Foo()您的代码以两种方式引入了未定义的行为:(1)对对象调用两次析构函数。(2) 在析构函数之后调用对象的非静态成员。解释在特定编译器、优化设置或月相中实际看到的内容是毫无意义的,因为观察到的行为可能与其他编译器、优化设置不同,或者月亮的相位。你可以查看程序集,找出编译器从损坏的源代码中生成了什么。试图解释未定义的行为实际上没有任何意义,因为这可能只是编译器为优化代码所做的疯狂复杂的事情的结果。我听说UB的代码受到
if(false){\*…*\}
的影响。f的生命在作用域闭包处显式终止。。。“}@2785528不,它是隐式终止的。不是我使用它的方式;)@这与你如何使用它无关。这是关于标准的,也就是C++如何工作。当控件退出某个作用域时,该作用域中具有自动存储持续时间的对象的生存期结束。这是含蓄的。它可能在
}
上,可能在
返回上,也可能在异常上。您不必显式地结束变量的生命周期。正如我上面所说的,它是隐式的。这篇文章的4个答案中有2个:“清除main()中分配的堆栈内存?”显示了右大括号的“显式”插入,以触发(DTOR的)“隐式”操作,释放一些自动内存供重用。(明确的:清楚详细地陈述,不留任何混淆或怀疑的余地)(隐含的:暗示但不明确地表达)(4项中的其他2项是错误的。)
f.~Foo();
f.~Foo();
{
    Foo f;
    f.~Foo();
}