【发布时间】:2019-10-26 20:16:30
【问题描述】:
C++17(草案 N4659)[basic.compound]/3 说:
指针类型的每个值都是以下之一:
指向对象或函数的指针(指针被称为指向对象或函数),或
超过对象末尾的指针 ([expr.add]),或
该类型的空指针值 ([conv.ptr]),或
一个无效的指针值。
这些类别中的哪一个属于指向对象生命周期之外的已分配内存的指针,特别是以下程序中// (1) 到// (3) 和b 的值// (4)?
#include<new>
#include<algorithm>
struct S {
~S() { /* Non-trivial destructor */ }
};
struct T {
~T() { /* Non-trivial destructor */ }
};
int main() {
void* a = operator new(std::max(sizeof(S), sizeof(T)));
// (1)
a = new(a) S;
static_cast<S*>(a)->~S();
// (2)
a = new(a) T;
static_cast<T*>(a)->~T();
// (3)
operator delete(a);
void* b = operator new(42);
// (4)
operator delete(b);
}
在我的理解中,指针值在解除分配时变得无效,而不是在对象的生命周期结束时,但如果指针值是“pointer[s] to an object”,则指向 他们指向哪个对象?
【问题讨论】:
-
当内存被释放时,指向内存的指针变得无效。当对象不再存在时,指向对象的指针变得无效。对于具有析构函数的类型,该类型的实例(也称为对象)在其析构函数完成时将不复存在。在析构对象然后释放内存的删除表达式中,任何指向该对象的指针在析构函数完成时都将无效,并且任何指向其底层内存的指针在释放内存时都将无效(例如
operator delete()函数返回)。 -
AFAIK,
operator new返回一个指向已分配内存块的第一个字节的指针。您可以考虑链接中的注释“注意:指向 void 的指针没有指向对象的指针类型,但是,因为 void 不是对象类型。 — 结束注释”。a和b仍然指向内存。即使在对象被破坏之后。析构函数不会为分配的内存调用delete。也许在所有情况下它“正式”是一个“指向对象类型的指针”,但是您在这里通过使用<new>来组合概念,它重新引入了 C 风格的malloc和free类似的分配。 -
@JHBonarius 之前的句子确实说
void*是一个“对象指针类型”,引用的段落讨论了“指针类型”的每个值”,我认为它是“object pointer type”的supset。我完全知道operator new确实返回了一个指向已分配内存的指针,并且析构函数调用不会释放它。包含<new>是为了使非分配放置-新可用。std::free和std::malloc在<cstdlib>中声明,而不是<new>。 -
@Peter "当对象不再存在时,指向对象的指针变得无效。":这基本上是我的问题。但是请注意,“invalid pointer value”是一个已定义的术语,[basic.stc]/4 不允许将 invalid pointer value 传递给释放函数,这对我来说毫无意义。
-
是的,但它们实际上做同样的事情......
<new>有一个很好的层,所以会抛出一个bad_alloc异常,而不是返回 NULL。
标签: c++ pointers language-lawyer c++17