Pour obtenir une clé
d'essai remplissez le formulaire ci-dessous
Demandez des tariffs
Nouvelle licence
Renouvellement de licence
--Sélectionnez la devise--
USD
EUR
RUB
* En cliquant sur ce bouton, vous acceptez notre politique de confidentialité

Free PVS-Studio license for Microsoft MVP specialists
To get the licence for your open-source project, please fill out this form
** En cliquant sur ce bouton, vous acceptez notre politique de confidentialité.

I am interested to try it on the platforms:
** En cliquant sur ce bouton, vous acceptez notre politique de confidentialité.

Votre message a été envoyé.

Nous vous répondrons à


Si vous n'avez toujours pas reçu de réponse, vérifiez votre dossier
Spam/Junk et cliquez sur le bouton "Not Spam".
De cette façon, vous ne manquerez la réponse de notre équipe.

>
>
>
Storage duration

Storage duration

24 Jan 2022

Storage duration is the identifier's property that defines the rules according to which an object is created and destroyed. There are 4 types of storage duration: automatic, static, thread local and dynamic.

Storage duration is closely related to the lifetime of an object. For example, two global objects with the static storage duration property have the same lifetime – the entire program execution time. At the same time, two objects with dynamic storage duration will have different lifetimes. Their lifetimes depend on when the corresponding dynamic memory management functions are called.

Automatic storage duration

Objects that have automatic storage duration are created upon entry into the code block that encloses the objects. These objects are destroyed upon exit from the code block. Such objects are local objects declared without the static, extern, or thread_local specifiers.

Here's a synthetic code example:

#include <vector>
#include <string>

class Forecaster { .... };

float Convert(const std::string &temp);

std::vector<float>
PredictTemperatureForInterval(int first_day,
                              int last_day,
                              const Forecaster &forecaster)
{
  auto forecast = forecaster.Predict(GetTodayDate());
  if (first_day == last_day)
  {
    std::string single_temperature = forecast.GetTemperature(first_day);
    if (!Validate(single_temperature))
    {
      return {};
    }

    return { Convert(single_temperature) };
  }
  else
  {
    std::vector<float> multiple_temperatures;
    for (auto curr_day = first_day; cur_day < last_day; ++cur_day)
    {
      std::string curr_temperature = forecast.GetTemperature(curr_day);
      if (!Validate(curr_temperature)
      {
        return {};
      }
      multiple_temperatures.push_back(Convert(cur_temperature));
    }

    return multiple_temperatures;
  }
}

In the example, the forecast, single_temperature, multiple_temperatures and cur_day have automatic storage duration. However, the lifetime for each of the variables varies.

The lifetime of the forecast variable ends when execution reaches the end of the PredictTemperatureForInterval function body. The lifetime of single_temperature is than–branch of the if statement. The lifetime of multiple_temperatureselse–branch of the if statement; and the lifetime of cur_day — a body of the for loop.

Static storage duration

For objects that have static storage duration, storage is allocated when the program starts execution and deallocated when the program ends execution. In this case, the object itself is created before the first access to this object. Objects that have static storage duration are all identifiers declared at some namespace scope, plus those identifiers declared with static or extern specifier. For each identifier that has static storage duration, only one instance of the object is created.

Let's look at the example:

class Logger { .... };

static Logger Logger;

int Calc(int arg);

int CalcWithLogging (int arg)
{
  static int counter = 0;
  ++counter;
  Logger.Log(counter);
  return Calc(arg);
}

In this code fragment, the logger and counter variables have static storage duration. For both variables, the storage is allocated when the program starts execution. The logger variable is a global variable. Its initialization is the call of the Logger class default constructor. The initialization occurs before the main function starts executing. The counter variable is a local variable of the CalcWithLogging function. The variable initialization occurs during the first call of the function. If the CalcWithLogging function is not called during the execution of the program, the initialization of counter variable doesn't occur. At the same time, the storage for counter is allocated and deallocated accordingly.

Thread local storage duration

For objects that have thread storage duration, storage is allocated when the thread is initialized and deallocated when the thread ends. The object itself is created before the first access to this object. Each thread has its own instance of the object. For the identifier to have thread storage duration, it must be declared with the thread_local specifier. The declaration of an object that have threadstorage duration may also contain the static or extern specifiers. In this case, these specifiers do not affect the storage duration but determine its linkage.

Here's a synthetic code example:

#include <string>
#include <string_view>
#include <iostream>
#include <syncstream>
#include <thread>

thread_local std::string str;

void AppendSuffix(std::string_view suffix)
{
  str += suffix;
}

void ThreadFunc(const std::string &value)
{
  AppendSuffix(value);
  std::osyncstream { std::cout } << str;
}

int main()
{
  AppendSuffix("main");
  std::thread t1 { ThreadFunc, "thread 1 " };
  std::thread t2 { ThreadFunc, "thread 2 " };
  t1.join();
  t2.join();
  std::cout << str;
}

In this example, the str variable has thread storage duration. When executing the program, a copy of the str variable is created for each of the t1 and t2 streams. The program will show one of two outputs: "thread 1 thread 2 main", "thread 2 thread 1 main" — it depends on the execution order of the threads.

Dynamic storage duration

To create or destroy an object that has dynamic storage duration, you need to use special functions for dynamic memory management. To create such an object, for example, you can use the new operator. In this case, this object will exist until the corresponding delete operator is called. Let's look at the following code example:

void Foo()
{
  int *pInt = new int;
  *pInt = 12;
  cout << *pInt << '\n';
  delete pInt;
}

Here, the pInt variable has dynamic storage duration. The storage for the variable is allocated during the new operator execution and is deallocated when executing the delete operator.

Comments (0)

Next comments
Unicorn with delicious cookie
Nous utilisons des cookies pour améliorer votre expérience de navigation. En savoir plus
Accepter