【问题标题】:What's the requirement for storage duration of temporaries?临时文件的存储时长有什么要求?
【发布时间】:2011-10-30 09:44:15
【问题描述】:

考虑以下代码:

class Test() {
public:
    Test()
    {
       memset( buffer, 0, sizeof( buffer ) );
    }
    void Process()
    {
       printf( buffer );
    }
private:
    char buffer[1000];
};

int main()
{
    Test().Process();
    char buffer[1000] = {};
    print( buffer );
    return 0;      
}

我无法推断是否允许main中的buffer重用之前被class Test的临时对象占用的内存。根据标准自动存储(3.7.2/1)must persist for at least until the block ends

我找不到会强制临时对象使用自动存储的措辞,但 6.6/2 除外,其中描述了跳转语句并说 在退出范围 [...] 时,析构函数 (12.4)为所有具有自动存储持续时间 (3.7.2) 的构造对象(命名对象或临时对象)调用,这似乎暗示临时对象使用自动存储。

使用自动存储是否需要临时人员?上面代码中main 中的局部变量是否允许重用之前临时占用的内存,还是应该使用不同的存储?

【问题讨论】:

  • Lifetime of temporaries的可能重复
  • @FredOverflow:我不认为它是重复的,因为这个问题询问 memory 何时变得可重用,这是一个与生命周期不同的概念该内存中包含的对象。所以基本上这个问题是,“标准中的什么文本使内存在临时的生命周期结束后可以重用?”对我来说,应该允许实现是“显而易见的”,我只是不知道标准的哪一部分具体暗示了这一点。
  • @Steve:嗯,我想你是对的。

标签: c++ memory memory-management duration


【解决方案1】:

临时的生命周期(除非绑定到const&)延伸到完整表达式的末尾。在您的情况下,main 的第一行。允许编译器重用相同的内存,但是否重用是实现细节(即实现质量

12.2 [class.temporary]

/3 [...] 临时对象作为评估的最后一步被销毁 完整的表达式(1.9),(词法上)包含它们的创建点。[...]

/4 有两种上下文,其中临时对象在与完整表达式结尾不同的点被销毁。第一个上下文是当表达式作为定义对象的声明符的初始值设定项出现时。 [...]

/5 第二个上下文是引用绑定到临时对象时。

由于您也不例外,Test 临时属于第一类,并且在评估第一行的最后一步被销毁

【讨论】:

  • 为什么对象销毁会取消 3.7.2 的“最短持续时间”措辞?
  • 编辑后更有意义,但是单个语句算块吗?
  • 我见过确实重用内存的编译器(例如 Atari ST 上的旧 Pure C),我也见过其他不重用内存的编译器(例如 Visual Studio 2010)。另一方面,我见过的所有编译器都会重用寄存器,这些寄存器也用于自动存储。在 VS 中不重用堆栈内存的决定可能是为了帮助调试,因为一旦你有代码重用寄存器,或多或少相同的代码也可以用于管理堆栈空间。
  • @Steve Jessop:标准中没有引用(至少我知道)与临时对象的存储持续时间有关,所以我假设内存的持续时间没有被定义存储临时对象的位置可以绑定到对象的生命周期(请注意,您不能 - 至少直接 - 获取临时对象的地址或将其绑定到比临时对象寿命更长的引用)。
  • @Nawaz:是的,该临时文件的生命周期会延长到定义引用的范围结束(即定义 a 的块)
【解决方案2】:

3.7.2/1 专门讨论了块范围变量。那些确实具有必须持续整个块的存储空间。然而,正如您所发现的,临时变量确实具有自动存储持续时间,但不是块范围变量。 (参见 3.3.3,块作用域与名称相关联)。

【讨论】:

  • 临时文件没有自动存储期限。 §3.7 中讨论的存储持续时间实际上只适用于命名变量;至少还有两个:临时的和例外的。 (请注意,第 3.7.3 节以“块范围变量 [...]”开头,它不适用于临时变量,因为临时变量不是变量。)
  • 你确定吗? 3.7/2 专门指 12.2 临时对象:“静态、线程和自动存储持续时间与实现 (12.2) 隐式创建的对象相关联。”。 (而且我认为从 3.7.1 和 3.7.2 可以清楚地看出,临时对象既不是静态的也不是线程本地的)
  • 我确信这里有一个缺陷,因为所描述的持续时间都不可能适用于 §15.1/3 中描述的“异常对象”(这也是“由实现隐式创建的” ”。鉴于他们显然没有考虑过一个,假设他们没有考虑所有这些对象似乎是合理的。§3.7.3开头的措辞肯定表明那里的清单是详尽无遗的(而且它没有'不要提及临时工)。
【解决方案3】:

语法Test() 创建一个临时的。这与命名的对象不同:

Test iHaveAName;

命名对象具有块持续时间;它将一直存在到块结束。临时有表达式持续时间;当它所在的表达式结束时,它将被销毁。

因此,如果您执行 Test().Process(),则 Test() 临时值将足够长,以使 Process() 完成。

【讨论】:

  • 我认为当 char buffer[1000] 发生时,OP 会询问临时是否会存活足够长的时间,也就是内存被缓冲区重用;)
【解决方案4】:

Test 实例一直存在到 ; 那里。未指定buffer 是否重用用于Test 实例的存储。 AFAIK,标准中没有任何内容阻止编译器重用空间。

【讨论】:

    【解决方案5】:

    它是定义的实现。智能编译器可以通过对齐堆栈指针来优化代码,以便buffer 可以重用内存。

    【讨论】:

      猜你喜欢
      • 2011-10-29
      • 2012-06-28
      • 2011-10-20
      • 2012-09-16
      • 1970-01-01
      • 1970-01-01
      • 2011-03-10
      • 2018-07-26
      • 1970-01-01
      相关资源
      最近更新 更多