3

Consider the following code:

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;      
}

I can't deduce whether buffer in main is allowed to reuse the memory previously occupied by the temporary object of class Test. According to The Standard automatic storage (3.7.2/1) must persist for at least until the block ends.

I can't find phrasing that would force a temporary object to use automatic storage except 6.6/2 where a jump statement is described and says that on exit from a scope [...], destructors (12.4) are called for all constructed objects with automatic storage duration (3.7.2) (named objects or temporaries) which seems to imply that temporaries use automatic storage.

Are temporaries required to use automatic storage? Is the local variable in main in code above allowed to reuse the memory previously occupied by the temporary or should it use distinct storage?

Community
  • 1
  • 1
sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • possible duplicate of [Lifetime of temporaries](http://stackoverflow.com/questions/4214153/lifetime-of-temporaries) – fredoverflow Aug 19 '11 at 08:46
  • @FredOverflow: I don't think it's a duplicate as such, because this question asks when the *memory* becomes re-usable, which is a distinct concept from the lifetime of the object contained in that memory. So basically this question is, "what text in the standard makes the memory re-usable as soon as the lifetime of the temporary is over?" It's "obvious" to me that the implementation should be allowed to, I just don't know what part of the standard specifically implies that. – Steve Jessop Aug 19 '11 at 08:53
  • @Steve: Hm, I guess you're right. – fredoverflow Aug 19 '11 at 08:56

5 Answers5

7

The lifetime of the temporary (unless bound to a const&) extends to the end of the full expression. In your case the first line in main. The compiler is allowed to reuse the same memory, but whether it does or not is an implementation detail (i.e. quality of implementation)

12.2 [class.temporary]

/3 [...] Temporary objects are destroyed as the last step in evaluating the full-expression (1.9) that (lexically) contains the point where they were created.[...]

/4 There are two contexts in which temporaries are destroyed at a different point than the end of the full expression. The first context is when an expression appears as an initializer for a declarator defining an object. [...]

/5 The second context is when a reference is bound to a temporary.

Since you are in neither exception, the Test temporary falls into the first category and is destroyed as the last step of the evaluation of that first line.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • Why would object destruction cancel out the "minimum duration" wording of 3.7.2? – sharptooth Aug 19 '11 at 07:44
  • It makes more sense after the edit, but is a single statement considered a block? – sharptooth Aug 19 '11 at 07:54
  • I have seen compilers which do reuse the memory (e.g. old Pure C on Atari ST) and I have seen others which do not (e.g. Visual Studio 2010). On the other hand, all compilers I have seen do reuse registers, which are also used for automatic storage. The decision to not reuse the stack memory in VS could be intended to aid debugging, as once you have the code reusing registers, more or less the same code could be used to manage stack space as well. – Suma Aug 19 '11 at 08:00
  • @Suma: LLVM does not reuse stack space, but they plan doing so. The issue, as I understand, is that the stack -> register optimization is *easy* (somewhat) because it is just a storage issue. On the other hand, stack reuse is directly bound to the lifetime of the objects, and this is language dependent, thus the IR requires specific instructions to know when a language considers a variable to be alive. FYI: this optimization is known as stack coloring. – Matthieu M. Aug 19 '11 at 08:39
  • I don't think this answers the question, since in principle the lifetime of an object is not the same as the duration of the memory that the object occupies, and destroying an object does not in general free that memory. It's not immediately clear that the standard intends there to be no difference in the case of temporaries, although of course it would make sense to say that there's no difference, and that the memory doesn't persist beyond the lifetime of the object. – Steve Jessop Aug 19 '11 at 08:47
  • @sharptooth: The *minimum duration* rules is for variables, not for temporaries. The mapping of temporary->variable by considering a single statement block is *false*, but I thought it could be used as a metaphor. I am removing that line now. – David Rodríguez - dribeas Aug 19 '11 at 08:47
  • 1
    @Steve Jessop: There is no quote (at least that I know of) in the standard that relates to the storage duration of temporaries, so my assumption that, not being defined, the duration of the memory where the temporary is stored can be bound to the lifetime of the object (noting that you cannot --at least directly-- obtain the address of a temporary or bind it to a reference that outlives the temporary). – David Rodríguez - dribeas Aug 19 '11 at 08:59
  • @David: You said `The lifetime of the temporary (unless bound to a const&) extends to the end of the full expression.`. Does it mean that if I write `const A & a = A();`, then the temporary lives longer than the end of the full expression? – Nawaz Aug 19 '11 at 09:29
  • 1
    @Nawaz: Yes, the lifetime of that temporary is extended until the end of the scope in which the reference is defined (i.e. the block where `a` is defined) – David Rodríguez - dribeas Aug 19 '11 at 10:47
  • @David: If I write `struct B { const A & a; B(const A& a) : a(a){} }; B b = A();`, then? – Nawaz Aug 19 '11 at 10:50
  • @Nawaz: No, that will not do it. The reference that you bind to the temporary is the argument of the constructor, and the lifetime will be extended for the scope of that reference, which is just the constructor call. The reference inside the B object does not extend the lifetime of the temporary any longer (it is not directly bound to the temporary, but to another reference) Note that the compiler inside `B( A const& a )` does not even know if `a` refers or not to a temporary, so it cannot make decisions. – David Rodríguez - dribeas Aug 19 '11 at 10:54
  • @Matthieu: Storing variables in registers usefully always includes some kind of register coloring, which seems similar to stack coloring to me, however I understand with objects being of various size on stack the issue may be a bit more complex. – Suma Aug 19 '11 at 13:03
  • @Suma: I think the principles are similar indeed, however the lifetime of an object is intrisic to a language, whereas whether an object is bound to a stack or to a register is (baring some language magic like assembly or C/C++ `register` allow) solely a compiler's to decide. Chris Lattner (Lead of LLVM) commented on it in http://stackoverflow.com/questions/7089035/at-what-moment-is-memory-typically-allocated-for-local-variables-in-c he references notes for LLVM developments http://nondot.org/sabre/LLVMNotes/MemoryUseMarkers.txt – Matthieu M. Aug 19 '11 at 13:30
3

3.7.2/1 specifically discusses block-scope variables. Those do have storage that must last the block. However, as you discovered, temporaries do have automatic storage duration, but are not block-scope variables. (See 3.3.3, block scope is associated with names).

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • Temporaries do not have automatic storage duration. The storage durations discussed in §3.7 really only apply to named variables; there are at least two more: temporaries, and exceptions. (Note that §3.7.3 starts with "Block-scope variables [...]" It does not apply to temporaries, since temporaries aren't variables.) – James Kanze Aug 19 '11 at 08:43
  • Are you sure? 3.7/2 specifically refers to 12.2 Temporary objects : "Static, thread, and automatic storage durations are associated with objects [...] implicitly created by the implementation (12.2).". (And I think that it's clear from 3.7.1 and 3.7.2 that temporaries are neither static nor thread local) – MSalters Aug 19 '11 at 09:02
  • I'm sure that there is a defect here, since none of the durations described could possibly apply to the "exception object" described in §15.1/3 (which is also "implicitly created by the implementation". Given that they've obviously not considered one, it seems reasonable to suppose that they've not considered all such objects. And the wording at the start of §3.7.3 certainly suggests that the list there is exhaustive (and it doesn't mention temporaries). – James Kanze Aug 19 '11 at 09:12
2

The syntax Test() creates a temporary. This is different from an object that is named:

Test iHaveAName;

A named object has block duration; it will live until the block ends. A temporary has expression duration; it will be destroyed when the expression it is on ends.

So, if you do Test().Process(), the Test() temporary will live long enough for Process() to finish.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • I think what OP asks if whether temporary will live long enough when char buffer[1000] occurs, aka, memory is reused by buffer;) – Eric Z Aug 19 '11 at 07:41
1

The Test instance lives until the ; there. Whether the buffer reuses the storage used for the Test instance is unspecified. AFAIK, there is nothing in the standard preventing the compiler from reusing the space.

wilx
  • 17,697
  • 6
  • 59
  • 114
0

It's implementation defined. A smart compiler may optimize the code by aligning the stack pointer so that the memory can be reused by buffer.

Eric Z
  • 14,327
  • 7
  • 45
  • 69