【问题标题】:Are pointers to allocated memory outside object's lifetime "invalid pointer[s]" or "pointer[s] to an object"?指向对象生命周期之外分配内存的指针是“无效指针[s]”还是“指向对象的指针[s]”?
【发布时间】: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 不是对象类型。 — 结束注释”。 ab 仍然指向内存。即使在对象被破坏之后。析构函数不会为分配的内存调用delete。也许在所有情况下它“正式”是一个“指向对象类型的指针”,但是您在这里通过使用 &lt;new&gt; 来组合概念,它重新引入了 C 风格的 mallocfree 类似的分配。
  • @JHBonarius 之前的句子确实说void* 是一个“对象指针类型”,引用的段落讨论了“指针类型”的每个值”,我认为它是“object pointer type”的supset。我完全知道operator new 确实返回了一个指向已分配内存的指针,并且析构函数调用不会释放它。包含&lt;new&gt; 是为了使非分配放置-新可用。 std::freestd::malloc&lt;cstdlib&gt; 中声明,而不是 &lt;new&gt;
  • @Peter "当对象不再存在时,指向对象的指针变得无效。":这基本上是我的问题。但是请注意,“invalid pointer value”是一个已定义的术语,[basic.stc]/4 不允许将 invalid pointer value 传递给释放函数,这对我来说毫无意义。
  • 是的,但它们实际上做同样的事情......&lt;new&gt; 有一个很好的层,所以会抛出一个 bad_alloc 异常,而不是返回 NULL。

标签: c++ pointers language-lawyer c++17


【解决方案1】:

这些类别中的哪一个属于指向对象生命周期之外的已分配内存的指针,特别是以下程序中// (1)// (3)b 的值// (4)

从分配函数返回的指针值(// (1) 上的a// (4) 上的b)目前没有指定,并且几乎不可能根据 [basic.compound]/3 中的分类法对它们进行分类,见https://groups.google.com/a/isocpp.org/d/msg/std-discussion/4NQawIytVzM/eMKo2AJ9BwAJ

在我的理解中,指针值在释放时变得无效,而不是在对象的生命周期结束时,但如果指针值是“指向对象的指针”,它们指向哪个对象?

当对象还活着时他们指向的对象。

【讨论】:

  • 啊好吧,有道理。我假设也有一种叶子打开了我被允许对从operator new 返回的指针做的事情,例如是否总是允许我复制/传递它(实现为无效指针定义)或将其转换为其他对象指针类型(允许特定目标类型的对象超出生命周期)。
  • "指向当对象存在时他们指向的对象。" new(a) 中,因此它们是在同一空间内创建的。而且刚刚解释了分配函数返回的指针没有指定,为什么这么说呢?
  • 不,指向已分配的内存空间 This 脚注暗示指针可以指向不在其生命周期内的对象。
  • 是的,好的,是的...但是operator new() 是一个例外,因为结果指针指向分配的内存部分的第一个字节,该部分“从未”被首先是对象...所以这有点像鸡蛋的故事...似乎我们必须推理,直到现实符合标准...这是相反的...我认为标准不完整: 太严格了。
【解决方案2】:

就基本运行时概念而言,所有 C++ 标准都是一团糟

什么是左值?它需要能够引用尚未创建的对象。 (指针也一样。)

什么时候创建的对象不存在?它们会在需要它们之前出现吗?

对我来说,最好的方法是假设所有对象类型都存在于内存中适合它们的任何地方。这里的许多人告诉我这是疯狂和矛盾的,但没有人指出矛盾。

【讨论】:

  • 它们会在需要之前出现吗?”:我认为这基本上是提案 P0593r5 背后的想法,它可能仍会成为 C++20 的一部分。
  • @uneven_mark 我还无法理解现有的标准散文 re:对象的生命周期,obj 将占用的存储空间。从什么时候开始可以使用future?在我看来 obj 存在,并且在存在期间定义了一个生命周期
猜你喜欢
  • 2021-08-12
  • 1970-01-01
  • 2023-02-09
  • 2011-04-24
  • 2018-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-06
相关资源
最近更新 更多