Our website uses cookies to enhance your browsing experience.
Accept
to the top
close form

Fill out the form in 2 simple steps below:

Your contact information:

Step 1
Congratulations! This is your promo code!

Desired license type:

Step 2
Team license
Enterprise license
** By clicking this button you agree to our Privacy Policy statement
close form
Request our prices
New License
License Renewal
--Select currency--
USD
EUR
* By clicking this button you agree to our Privacy Policy statement

close form
Free PVS‑Studio license for Microsoft MVP specialists
* By clicking this button you agree to our Privacy Policy statement

close form
To get the licence for your open-source project, please fill out this form
* By clicking this button you agree to our Privacy Policy statement

close form
I am interested to try it on the platforms:
* By clicking this button you agree to our Privacy Policy statement

close form
check circle
Message submitted.

Your message has been sent. We will email you at


If you haven't received our response, please do the following:
check your Spam/Junk folder and click the "Not Spam" button for our message.
This way, you won't miss messages from our team in the future.

>
>
>
Storage duration

Storage duration

Jan 24 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.

Popular related articles


Comments (0)

Next comments next comments
close comment form