【问题标题】:Does C++ new operator guarantee that the returned pointer will not change its value?C++ new 运算符是否保证返回的指针不会改变其值?
【发布时间】:2014-09-27 07:25:44
【问题描述】:

在 C++ 中:

const size_t N = 1000;
int* p = new int[N];// time=t0

我的程序只有一个线程,在分配内存给p后,我的程序只会读取p指向的内存。

标准对p 的价值有何评价?

p 是否会保留它在 time=t0 时获得的值,直到 deletep 出现?

或者,操作系统可以自行决定重新分配p指向的内存吗?

是否取决于N的值?

【问题讨论】:

  • 变量的值永远不会自行改变。
  • 不同的东西。 p 可以保持它的值,并且p 指向的内存可以重新分配。
  • @juanchopanza 那么操作系统可以自行决定(没有我写的明确代码)重新分配内存吗?
  • @uvts_cvs 如果内存不足或调用未定义行为 (UB),它可以做到。但重点(不是双关语)是指针只是一个保存数字的变量。该数字不会自行改变(除非您调用 UB,在这种情况下,无论如何,所有赌注都是关闭的。)
  • 有趣的问题,我回到这个问题是因为好奇是否有人会找到一个标准的报价来证明它。

标签: c++ memory-management operating-system standards


【解决方案1】:

p 的值在创建后不能移动。该标准使这样做毫无用处:

3.7.4.1 分配函数

...如果请求成功,返回的值应该是一个非空指针值(4.10)p0,不同于任何 先前返回的值 p1,除非该值 p1 随后被传递给操作员 delete。

(引用标准结束)


因此,如果在运行时,由于合并某些内存碎片等原因决定将 p 移动到另一个地址,则标准已使原始 p 指向的空间不可能被另一个内存分配使用。空间将被浪费。

【讨论】:

    【解决方案2】:

    标准的内存模型和预期语义谈到了实现必须符合的可观察行为(参见标准的第 1.7 段 - C++ 内存模型 - 至 1.10 - 多线程执行和数据竞争)( 1))。这种可观察的行为应与标准中描述的抽象机器之一相匹配。它将程序的内存定义为一组字节序列,可以通过副作用操作(内存上的 I/O)对其进行修改。指针本身就是存储在内存中的字节序列,因此遵循相同的规则。该模型还指定了未定义行为的情况,任何事情都可能发生,包括内存损坏。此外,多线程程序可能会通过竞态条件(参见 1.10)“在其背后”修改内存(我自己的措辞,而不是实际引用)。

    new 运算符通过使用分配函数来工作,分配函数返回内存地址,并且还必须遵守可观察行为的规则。

    话虽如此,第 1.9 段(程序执行)在第 8 点中指出,在符合要求的实施中,最低要求是:

    对 volatile 对象的访问严格按照抽象机的规则进行评估。

    换句话说,尽管程序应该呈现与标准中描述的模型所展示的结果相同的结果,但只有volatile 可以保证完全按照标准中的描述进行观察。可能无法以一致的方式观察到非易失性存储(如果您已经在优化代码上使用过调试器,您可以清楚地看到内存内容更新中与程序源实际指定的内容有关的奇怪模式)。 另一个重要的一点是new 运算符是可重载的,这意味着标准中描述的默认行为可能会被覆盖。如果标准的最低一致性实现(即,仅强制执行volatile 变量观察)运行一个程序,其中new 已被覆盖并且不依赖volatile 数据来跟踪其内存堆,通过优化和强内联,返回的指针的值可能不会立即在存储它们的变量中可见。如果优化通过确定变量的生命周期可以从程序描述的内容中缩短,那么与该变量对应的内存位置也可能被重新利用,并且它的内容也可以在调试器中改变和观察,尽管程序没有指出这样的更新。然而,编译器的工作是确保程序的执行符合预期的行为:从程序的角度来看,变量将在其整个生命周期内保持其值,并且除非程序指定它否则不会改变通过内存模型允许的任何方式进行更新。

    在您的示例中,如果在您的程序中在您的程序中分配p 之后多次访问变量p,您将不会注意到自该分配以来它所包含的值发生了变化,标准要求它。如果您尝试通过某个外部设备观察该变量的内存位置,您就会跳出标准的抽象内存模型,并且可能会看到其内容的变化。

    (1) 使用修订版 N3485 作为参考,段落编号在以后的修订版中可能已更改。

    【讨论】:

      【解决方案3】:

      p 的值只是一个内存位置。分配后不会改变。它指向的内存可以改变。它不会被操作系统更改。它可以由您的程序更改。如果您只是分配一个整数数组(例如),并为每个整数分配值。你可以放心,除非你明确地覆盖它们(或者有一个这样做的错误),否则这些值不会改变。

      【讨论】:

        【解决方案4】:

        堆分配的地址将保持不变,变量不会在没有您影响的情况下更改其值。您的 p 甚至会在删除后保留其值,但如果您尝试访问它,您将触发(希望)一个分段错误。 N 的值不起作用。

        【讨论】:

        猜你喜欢
        • 2014-12-24
        • 2015-08-12
        • 1970-01-01
        • 2016-02-12
        • 1970-01-01
        • 2011-06-27
        • 2011-02-18
        • 2012-07-24
        • 1970-01-01
        相关资源
        最近更新 更多