11

Can someone explain to me the difference between storage duration and lifetime of objects? I think they denote the same thing. I found a definition that says:

Lifetime of an object is equal to or is nested within the lifetime of its storage.

So according to this, there is a little difference I can't see. Also, I'll be very grateful if someone explains to me these concepts in low level terms. I'd rather think about memory, adresses, and data than about high level stuff. Thanks.

Link to the definition above

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
LearningMath
  • 851
  • 4
  • 15
  • 38

5 Answers5

18

Storage duration is one of four words:

  • automatic
  • static
  • dynamic
  • thread (local)

That's it. It tells you what rules apply for when the object will be created and destroyed.

Lifetime is the portion of the runtime of the program during which the object is usable. Generally this is from construction until destruction, but for trivial types (those with no constructor or destructor) it's "from when the memory is allocated until the memory is either released or used for another object".

So the two are related, but they aren't quite the same thing. Two objects with different storage durations could have related and almost-identical lifetimes (for example an automatic unique_ptr and the dynamic object it manages), and two objects with the same storage duration can have completely different lifetimes (especially two dynamic objects).

IInspectable
  • 46,945
  • 8
  • 85
  • 181
Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • You want to say that if we have two objects that are created by the operator `new` (dynamic objects), they have the same storage duration but if we `delete` the first one on the 50th line of code and the second one on the 100 line of code, they will have different lifetime. Am I right? – LearningMath Jan 27 '14 at 21:50
  • The lifetime of the object owned by a `unique_ptr` isn't the same as that of the `unique_ptr`. The `unique_ptr` will normally have a lifetime corresponding to automatic storage duration; the object it points to will have dynamic lifetime, which is radically different. If you return a `unique_ptr`, for example, the local variable's lifetime will end, but not the lifetime of the object it pointed to. – James Kanze Jan 27 '14 at 22:52
  • @JamesKanze: that's true. Note that I didn't say every `unique_ptr` has the same lifetime as the object it manages. I said that was an example of objects that *could have* almost-identical lifetimes. – Steve Jessop Jan 27 '14 at 22:58
  • @SteveJessop Could you expand on this a little? Like what happens if I have a (local) static object and initialize it using `placement new`. Will the object's storage duration change from static to dynamic or does `placement new` behave differently than `new`? – Cerno Oct 26 '20 at 08:59
  • @Cerno: if you take a local static object and initialize it with placement `new`, then it still gets destructed at whatever time it otherwise would have been destructed, so it still has its original storage duration. That said, if you have a byte buffer with static storage duration, then construct something in it using placement new, then the object you constructed has dynamic storage duration, even though it just so happens to exist in the same memory location as the static byte buffer. – Steve Jessop Jan 25 '21 at 18:27
7

You walk in to a McDonald's and are presented with a menu. There are many different items on the menu, including a Big Mac, a Quarter Pounder w/Cheese, a hot apple pie, and the ever-disgusting Filet-O-Fish.

You walk up to the counter and order a Big Mac. You are presented with with a 3-layer bun, 2 "all beef" patties and some special sauce, all enclosed in a piece of paper.

The person behind you orders the same thing, and they are given their own burger. You both sit down and start to eat. You eat yours very quickly, but your neighbor barely touches his.

The 3rd person in line orders the Apple Pie, and they are given something entirely different. A little semi-cylindrical pastry filled with something resembling apples.

In this analogy, the printing on the menu is the storage duration, and the type of burger itself is akin to the object lifetime. Two different storage durations were selected; the Big Mac and the Apple Pie. Three objects were produced as a result: two burgers and one pastry. Two of those objects have the same general makeup, even though they are two distinct burgers, but the third is different. Two storage durations, three objects.


Your quote:

Lifetime of an object is equal to or is nested within the lifetime of its storage.

Is not a definition for "lifetime" or "storage duration", but simply relates the two. It tells you, given a "storage duration" of X you can expect a lifetime of Y.

In that sense, the two terms are really twos sides of the same coin. A particular storage duration yields a particular lifetime.

This is elaborated on in the (C++03) Standard:

3.8 Object Lifetime

1/The lifetime of an object is a runtime property of the object. The lifetime of an object of type T begins when: — storage with the proper alignment and size for type T is obtained, and — if T is a class type with a non-trivial constructor (12.1), the constructor call has completed. The lifetime of an object of type T ends when: — if T is a class type with a non-trivial destructor (12.4), the destructor call starts, or — the storage which the object occupies is reused or released.

3.7 Storage Duration

1/Storage duration is the property of an object that defines the minimum potential lifetime of the storage containing the object. The storage duration is determined by the construct used to create the object and is one of the following: — static storage duration — automatic storage duration — dynamic storage duration

John Dibling
  • 99,718
  • 31
  • 186
  • 324
3

In simple words, storage duration is the period in which the memory underlying the object is guaranteed to be available; lifetime is the period in which you can use it as an object of the specified type. The most obvious example of the difference is when you call std::vector<>::reserve; this allocates the memory for the corresponding number of objects, but they don't become available until you call some function which constructs them.

In other contexts: trivially constructed objects are considered to have a lifetime equal to their storage duration, but this isn't actually true; until the object has been initialized, there are only a limited number of things you can do with it (no lvalue to rvalue conversions, in particular). At the other end, the lifetime of objects with non-trivial constructors and destructors is considered to begin when you return from the constructor, and to end when you enter the destructor, but there are quite a number of things you can do with it while the constructor and destructor are running. And of course, as long as all you do is copy the address of the memory, the only thing which counts is storage duration.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
2

I'd rather think about memory, adresses, and data than about high level stuff.

Where the data get's stored depends on the several possibilities as pointed out by

  • automatic => on the function call stack (also see RAII)
  • static => on the (correctly initialized) global data section (also see RAII)
  • dynamic => on the heap (allocation from new() or malloc() calls)
  • thread (local) => on the specific thread's private data (Note: Trying to share thread private data directly between threads, leads to an exception.)

The Lifetime,- and such Storage Duration -, of your class instances is determined by the scope(s), they are shared within.
For threads of course, you might have concurrently shared scopes, and should obey this carefully.
In general check for unwanted copies, i.e. rvalue references.

The preferred paradigm to use with is RAII, which is very well supported by the memory management features of the latest smart pointer features.
The latter encapsulate the management of blocked scope { ... }, and an overall 'virtual' scope, that manages the lifetime of the encapsulated class instances for even dynamically allocated objects.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • I've read that lifetime and storage duration do not depend on scope. A name becomes unavailable when the scope ends but that doesn't mean that the memory allocated for the object goes away. If I create a dynamic object in a function and return the pointer to the object to main we can still access the object. – LearningMath Jan 28 '14 at 00:06
  • @J.M _'I've read that lifetime and storage duration do not depend on scope ...' I not necessarily meant a local scope of the current function. – πάντα ῥεῖ Jan 28 '14 at 11:38
  • i don't quite understand what you want to say. Could you please explain once again what you meant with this: `The Lifetime,- and such Storage Duration -, of your class instances is determined by the scope(s), they are shared within.` ? – LearningMath Jan 28 '14 at 18:51
  • @J.M. The main thread of your program and any further threads define their own (overall) scopes. When instances of heap allocated objects are shared between thread's they are shared between scopes. You're right (or at least the source you read), that the lifetime of a heap allocated object is not influenced by the scope (`{}`) within the `new()` call was made. But to handle their lifetimes properly, you'll need to make a decision where and when to `delete` them, so their scope is again some virtual construct including the `new()` and `delete` calls. More to follow ... – πάντα ῥεῖ Jan 28 '14 at 19:05
  • @J.M. ... That's why I mentioned smart pointers, these will encapsulate this 'virtual' scope, and boil it down to 'real' ones, that control instance lifetime and storage duration. – πάντα ῥεῖ Jan 28 '14 at 19:07
  • Didn't all threads share the same namespace scope? Also when we talk about scope we talk about usage of `names` not for the piece of memory that name refers to, right? – LearningMath Jan 29 '14 at 02:36
  • @J.M _'Also when we talk about scope'_ No, I'm not using the term scope here by this meaning only. – πάντα ῥεῖ Jan 29 '14 at 08:11
  • I don't know if I am really stupid and still don't get it or there's something wrong with the explanation. I went to tons of pages and read about threads, but I still can't understand what you really want to say about threads, scopes, etc. I will be very grateful if you clear this to me. We can go on chat to not add any more comments here. Also, you can give me some material to read on this if you find. Thanks for your effort really. – LearningMath Jan 29 '14 at 19:32
  • @J.M _'I don't know if I am really stupid'_ I don't think so. I suppose how lifetime is managed for stack allocated class instances (RAII as mentioned) is pretty clear for you (they'll be gone as soon the actual block of code is left). The lifetime of heap allocated class instances is determined by paired calls of `new()` and `delete`. Smart pointer implementations put the `delete` operation into their destructor functions conditionally. Thus the decision about the lifetime of the instance managed within is left to the smart pointer class. More to follow ... – πάντα ῥεῖ Jan 29 '14 at 19:42
  • @J.M ... One variant of a smart pointer is the `std::shared_ptr` class, which does reference counting for the managed instance. The reference counter is incremented for each copy of a `std::shared_ptr` and decremented in its destructor. If the counter becomes zero, `delete` is called for the managed instance. Thus the last holder for such reference going out of scope determines the lifetime of the heap allocated object. Hope this makes it clearer for you. – πάντα ῥεῖ Jan 29 '14 at 19:47
  • I am not familiar with RAII. I'm reading now about it. Could you please read my answer below and see if it's correct or you have something to add? – LearningMath Jan 29 '14 at 21:40
1

This is what I understand so far (and think it's right):

The only situation where lifetime can differ from storage duration is when using dynamic objects. For example two static or two automatic objects have the same lifetime. We can have automatic object and dynamic object (different storage durations) and those two to have the same lifetime if we end the dynamic object's lifetime at the end of the function scope for example. That's because we can end a dynamic object's lifetime whenever we want and get the same lifetime as some other object with different storage duration. Also, we can have two different dynamic objects and give a shorter lifetime to the first object than the second one by freeing the memory the first object occupies.

At the end of the day, these definitions hold:

Lifetime of an object starts when it's constructor is called and lasts until it's destructor is called. ( or from it's creation to it's deletion)

Storage duration in simple words "guarantees" that the object that will be created will be usable (it can use the memory allocated for it) until the moment specified by it. For example if it is static object, it will last until the program terminates, automatic when the function ends and dynamic one when the user calls delete.

Correct me please if I am wrong somewhere.

LearningMath
  • 851
  • 4
  • 15
  • 38
  • I think there's no really wrong statement here, but may be too narrow from a bigger picture view. Since dynamic allocation (`new()`) of an instance can occur in different program execution paths' as the `delete` call (it's not really constructor/destructor call, because memory (de-)allocation is done prior/after those calls). – πάντα ῥεῖ Jan 29 '14 at 22:30
  • 1
    Then how to get the bigger picture? I really want to understand all of this, i mean ALL, because i want to know how it works under the hood and understand all the concepts very well. I put very much effort in this so I'm not going to give up at all. Could you give me some links, literature or whatever material to read to better understand all of this? Again, big thank you for all your answers. – LearningMath Jan 29 '14 at 23:10