内存重用和UB
Memory reusing and UB
以下代码是否生成UB?
#include <iostream>
#include <climits>
struct A
{
~A(){ std::cout << "Non-trivial" << std::endl; }
};
int main()
{
A a;
new (&a) A;
} //UB?
演示
标准N3797::3.8/8 [basic.life]
如果程序以static结束T类型对象的生存期(3.7.1)、线程(3.7.2)或自动(3.7.3)存储持续时间,如果T有一个非平凡的析构函数,程序必须确保当发生隐式析构函数调用;否则程序未定义。
我认为在main函数的左边没有UB,因为&a
指向与最初分配的类型相同的类型。
[3.8/4]程序可以通过重用对象占用的存储,或者通过显式调用具有非平凡析构函数的类类型对象的析构函数,来结束任何对象的生命周期。对于具有非平凡析构函数的类类型的对象,在对象所占用的存储被重用或释放之前,程序不需要显式调用析构函数;但是,如果没有对析构函数的显式调用,或者如果删除表达式(5.3.5)没有用于释放存储,则不应隐式调用析构函数,并且任何依赖于析构函数产生的副作用的程序都具有未定义的行为。
你的程序"依赖"析构函数产生的副作用吗?清楚:
-
可观察程序的输出在变化的意义上取决于析构函数是否运行
-
如果析构函数不运行,则
cout
缓冲区的状态、位置等将不同,并且 -
在程序终止时留下来执行的刷新动作可能不同。
可以合理地说,后面的程序行为/流取决于析构函数是否运行,这意味着技术上未定义的行为。
尽管如此,我还是敢说,标准的目的是警告析构函数操作,如不释放锁或减少引用计数器,可能会产生令人不快的后果,如以后挂起或泄漏,并且在实践中,在所有实际的编译器上,您发布的程序将如您所期望的那样运行。
同样值得注意的是,通常情况下,如果构造函数抛出并且范围在该内存位置没有有效对象的情况下展开,那么这种做法是危险的。
这是未定义的行为,但不是因为您引用的原因:
[基本寿命]/4
[…]如果没有显式调用析构函数或如果删除表达式(5.3.5)未用于释放存储,则析构函数和任何依赖于在析构函数产生的副作用上有未定义的行为。
由于析构函数有副作用,在重用内存之前,必须显式调用析构函数
A a;
a.~A();
new (&a) A;
- 将字符串存储在c++中的稳定内存中
- C++ 指针的内存地址和指向数组的内存地址如何相同?
- Win32编译器选项和内存分配
- 当vector是tje全局变量时,c++中vector的内存管理
- 带内存和隔离功能的SQLite
- 是否可以通过C++扩展强制多个python进程共享同一内存
- 迭代时从向量和内存中删除对象
- 在C++中打印指向不同基元数据类型的指针的内存地址
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值
- 多个文件的内存分配错误"在抛出 'std :: bad_alloc' what (): std :: bad_alloc 的实例后终止调用" [C++]
- 为什么示例代码访问IUnknown中已删除的内存
- 如何在C++类内存结构中创建"spacer"?
- 从构造函数抛出异常时如何克服内存泄漏
- malloc() 可能出现内存泄漏
- 如何理解将半精度指针转换为无符号长指针和相关的内存对齐
- 在调用FreeLibrary后,释放动态链接到具有相同版本的CRT堆的DLL的内存
- 如何针对特定情况调试和修复此双自由内存损坏问题
- 类型总是使用其大小存储在内存中吗
- 有没有一种方法可以测量c++程序的运行时内存使用情况
- 内存重用和UB