【发布时间】:2020-12-25 10:52:20
【问题描述】:
在下面的简短示例中,关于指针f 指向或用于在从main 返回之前指向的对象可以说什么?
#include <vector>
struct foo {
std::vector<int> m;
};
int main()
{
auto f = new foo;
f->~foo();
}
我相信 foo 不再是 f 曾经指向的对象。我收到很多 cmets 说这可能不正确,而是可能有一个对象 foo 处于已破坏、死亡或其他无效状态。
对于显式销毁但其存储仍然有效的对象的存在,语言标准有什么说法?
换句话说,是否可以合理地说f 处仍有一个对象超出其生命周期?有没有对象不在其生命周期内,没有开始构造,也没有被销毁?
编辑:
很明显,当对象不在其生命周期内时,它也可以存在。在构造和销毁期间,有一个对象,它的生命周期尚未开始或已经结束。来自https://timsong-cpp.github.io/cppwp/intro.object#1:
[...] 一个对象在其构建期间([class.cdtor])、在其整个生命周期以及在其销毁期间([class.cdtor])占用一个存储区域。 [...]
但是在f->~foo(); 之后,f 指向的对象(我们称之为o)没有被构造,它不在其生命周期内,也没有被破坏。我对本节的阅读是 o 不能再占用存储空间,因为它不在任何枚举的情况下。似乎这意味着不再有 o 并且不再有指向 o 的指针。相反,如果您有一个指向 o 的指针,那么该指针将指向 o 无法占用的存储空间。
编辑 2:
如果不再有对象,那么foo 有什么样的价值?似乎它可以拥有的唯一合理的可能值是指向对象的指针,这与陈述相矛盾。见this question。
【问题讨论】:
-
来自 C++20 eel.is/c++draft/basic.life#5 我相信适用,但我认为在那之前情况有所不同——不确定。
-
@N.Shead 有趣的是,如果您依赖副作用,则只有 UB 不调用析构函数。虽然它与问题无关,但似乎如果我在
f指向的对象上执行放置new,这将是明确定义的行为,但也会泄漏f->m可能持有的任何内存?或者我会被认为是依赖它会被释放的副作用? -
我想这取决于您是否认为释放内存是一种副作用。据我所知,除了“写入文件”之外,该标准对于副作用的确切含义非常宽松。我怀疑这通常是 UB,虽然我不能肯定地说。
-
@FrançoisAndrieux
f->m使用的任何内存都会在~foo()析构函数中释放,无论是手动调用还是自动调用。在发布的代码中会泄漏的是new分配的对象内存。为了清理它,您需要在f上放置new,然后在delete f;上放置。 -
@dxiv 我之前的评论是假设如果
f->~foo();被new (f) foo;替换并在之后尽最大努力清理并且f->m有容量。看到我以 “虽然它与问题无关” 开头那部分。在那种假设的情况下,我不清楚是 UB 还是定义明确但第一个foo泄露了它的成员的内部资源。
标签: c++ language-lawyer lifetime object-lifetime