在这种情况下显式调用时,std::cout 如何更改析构函数的行为?
How does std::cout change destructor's behavior when explicitly called in this case?
我正在尝试显式调用对象的析构函数。以下代码按预期工作:
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程序所做的任何事情。
相关文章:
- 什么时候调用组成单元对象的析构函数
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 内联映射初始化的动态atexit析构函数崩溃
- 什么时候调用析构函数
- 优先顺序:智能指针和类析构函数
- C++-明确何时以及如何调用析构函数
- 使用基类指针创建对象时,缺少派生类析构函数
- 在c++中使用向量时,如何调用构造函数和析构函数
- 重载运算符new[]的行为取决于析构函数
- 我需要知道编译器如何在cpp中使用析构函数
- 为什么在使用转换构造函数赋值后调用C++类的析构函数?
- 析构函数调用
- 通过引用传递-为什么要调用这个析构函数
- 对具有动态分配的内存和析构函数的类对象的引用
- 重载 -> shared_ptr 个实例中的箭头运算符<interface>,接口中没有纯虚拟析构函数
- 在这种情况下显式调用时,std::cout 如何更改析构函数的行为?
- "virtual"对C++析构函数有何影响?
- 更改析构函数顺序
- C++03 12.4/12对通过指针显式调用基类析构函数有何说明
- 结果中未显示由析构函数更改的全局变量