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

How does std::cout change destructor's behavior when explicitly called in this case?

本文关键字:析构函数 何更改 cout 调用 std 这种情况下      更新时间:2023-10-16

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

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 

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

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

不要。只是不要。这很糟糕。很差。永远不要这样做,尤其是当你不了解析构函数是什么时。

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

显式析构函数调用不起作用

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

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

之后打印时,它可以复制值,添加 10,然后打印副本。 但编译器会将其就地递增并打印出来。

根据C++标准,具有未定义行为的程序在未定义行为之前和之后对其行为没有任何限制。

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

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

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