Non-local object with thread storage duration - c++

It is unclear why does object with thread storage duration is not default-initialized? For instance:
#include <iostream>
using std::cout;
struct S
{
S(){ cout << "S\n"; }
~S(){ cout << "~S\n"; }
};
thread_local S s;
int main()
{
}
IdeOne
stdout is empty. But I expected that stdout would contain
S
~S
It is because sec. 8.5/12 N3797:
If no initializer is specified for an object, the object is
default-initialized
This does not say anything about storage duration of the object.

Related

C++ Which thread calls the destructor

If I create a thread_local object, its destructor is called on the thread it was created on:
#include <iostream>
#include <thread>
#include <chrono>
struct MyStruct {
~MyStruct() {
std::cout << "Destructed on thread #" << std::this_thread::get_id() << std::endl;
}
};
void f() {
thread_local MyStruct myStruct;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
int main() {
std::thread t(f);
std::cout << "Created thread #" << t.get_id() << std::endl;
t.join();
}
Created thread #16920
Destructed on thread #16920
Does the C++ standard guarantee this behaviour? It only states this:
A variable with thread storage duration shall be initialized before
its first odr-use (6.2) and, if constructed, shall be destroyed on
thread exit.

Static inline members initialization order

A well known problem in C++ is the static initialization order fiasco. Is it still considered a problem when one use C++17 static inline members?
Here an example where a static inline member is used in two different translation units (a.cpp and b.cpp) as an initializer for two non-inline static members:
counter.hh
#pragma once
#include <vector>
#include <fstream>
class Counter
{
public:
Counter() { std::ofstream os("o.txt", std::ofstream::app); os << "Counter created" << std::endl; }
~Counter() { std::ofstream os("o.txt", std::ofstream::app); os << "Counter destroyed" << std::endl; }
void add_instance()
{
++m_instances;
std::ofstream os("o.txt", std::ofstream::app); os << "Counter increased: " << m_instances << std::endl;
}
void remove_instance()
{
--m_instances;
std::ofstream os("o.txt", std::ofstream::app); os << "Counter decreased: " << m_instances << std::endl;
}
private:
int m_instances = 0;
};
class Object
{
public:
Object(Counter & counter) : m_counter(counter)
{
m_counter.add_instance();
std::ofstream os("o.txt", std::ofstream::app); os << "Object created" << std::endl;
}
~Object()
{
m_counter.remove_instance();
std::ofstream os("o.txt", std::ofstream::app); os << "Object destroyed" << std::endl;
}
private:
Counter & m_counter;
};
struct C
{
static inline Counter static_counter{};
};
a.hh
#pragma once
#include "counter.hh"
struct A
{
static Object static_a; //not inline
};
a.cpp
#include "a.hh"
Object A::static_a{C::static_counter};
b.hh
#pragma once
#include "counter.hh"
struct B
{
static Object static_b; //not inline
};
b.cpp
#include "b.hh"
Object B::static_b{C::static_counter};
main.cpp
#include "a.hh"
#include "b.hh"
int main() { }
output (with MSVC 16.1.2)
Counter created
Counter increased: 1
Object created
Counter increased: 2
Object created
Counter decreased: 1
Object destroyed
Counter decreased: 0
Object destroyed
Counter destroyed
I think that, with regard to the initialization, this practice is safe because the C++17 standard ensures that static inline members are: (1) always initialized before any use and (2) initialized only once across multiple translation units.
But I'd like to know if there are any hidden downsides in this pattern, for example related to the order of destruction of each variable across different TUs. Is it well-defined that both static_a and static_b are always destroyed before static_counter?
Yes, this is fine, since in every translation unit static_counter is defined before static_a/static_b. Destruction order is not guaranteed to be the reverse (given threads, this is meaningless anyway), but the reverse of each guarantee holds, so that works too.

Is a global boolean variable reliable during global destruction?

If I have a simple data type as a global variable -- like a boolean flag; specifically, something that doesn't have a destructor -- does that variable remain reliable even during global destruction? Or is that not guaranteed?
For example, would the result for the following code be well-defined?
Flag.h:
void SetFlagState(bool flag);
bool GetFlagState();
Flag.cpp:
#include <Flag.h>
namespace { // local declarations
bool g_flag;
}
void SetFlagState(bool flag)
{
g_flag = flag;
}
bool GetFlagState()
{
return g_flag;
}
Main:
#include <iostream>
#include <Flag.h>
class FlagChecker
{
public:
~FlagChecker()
{
std::cout << "Flag value: " << GetFlagState() << std::endl;
}
};
FlagChecker g_FlagChecker; // global instance; dtor will be called on exit
int main()
{
SetFlagState(true);
}
Yes, this is safe. The lifetime of the storage is the duration of the program. The chief issue during that lifetime is with the moment of initialization (via your g_Flagchecker). As there's no such thing "de-initialization" for built-in types, your g_flag remains valid as long as there's code executing in your process.

Destruction of thread_local objects

In the question Using QSqlQuery from multiple threads there was the outcome that thread storage solves the problem.
I made a simple demo code to be absolutely clear about C++11 thread_local specifier. The code below creates two threads which have ThreadLocal object as a local unique object. The Storage::get function is a thread specific singleton. Does the standard guarantee that ThreadLocal destructor is called on join or the exit of the thread function?
Compiled with GCC 5.4.0
(g++ -o main main.cpp --std=c++11 -lpthread)
#include <thread>
#include <mutex>
#include <string>
#include <chrono>
#include <iostream>
#include <atomic>
static std::mutex mtx;
struct ThreadLocal {
std::string name;
~ThreadLocal() {
mtx.lock();
std::cout << "destroy " << name << std::endl;
mtx.unlock();
}
};
struct Storage {
static ThreadLocal &get() {
/* Thread local singleton */
static thread_local ThreadLocal l;
static std::atomic<int> cnt(0);
l.name = std::to_string(cnt);
cnt++;
return l;
}
};
void thread() {
mtx.lock();
std::cout << Storage::get().name << std::endl;
mtx.unlock();
std::this_thread::sleep_for(std::chrono::seconds(1));
}
int main(int argc, const char **argv) {
std::thread t1(&thread);
std::thread t2(&thread);
t1.join();
t2.join();
}
If the object was constructed, it will be destroyed on the exit of the thread function. Pretty much in those exact words over at [basic.stc.thread]/2:
A variable with thread storage duration shall be initialized before
its first odr-use ([basic.def.odr]) and, if constructed, shall be
destroyed on thread exit.

Unhandled exception in ReferenceReturn.exe:

Please take a look at this simple code:
// A.h
#pragma once
#include <iostream>
class A
{
public:
A();
~A();
int a;
private:
};
A::A() :a{3}
{
}
A::~A()
{
std::cout << 42 << std::endl;
}
In Main.cpp I have a global function:
// Main.cpp
#include "A.h"
A GlobalGetAByValue(){
static A a{};
return a;
}
int main(){
A a = GlobalGetAByValue();
int val;
std::cin >> val;
return 0;
}
And now interesting - if in close a console with close button I have an exception in A's destructor. If I enter some values and press enter - console closes without exception. If I initialize variable a as local variable or if I create a pointer with new keyword and delete it just before return everything works fine.
So I only get this cout error in destructor when I'm using static A. But why?
As it said in section 3.6.3 "Termination" of the C++03 standard:
"Destructors for initialized objects of static storage duration (declared at block scope or at namespace scope) are called as a result of returning from main and as a result of calling exit."
so, i can make a suggestion, that when destructor called, there no any valid ostream object (like cout in this case).