Can I rely on a function-scoped static variable for a method called during program shutdown?
Clash Royale CLAN TAG#URR8PPP
up vote
6
down vote
favorite
Quick context: I'm seeing errors on program shutdown, that stem from dependencies between global members (::sigh::, I know, I know). One global variable's destructor might refer to another global -- and if that one's already been destructed, things get bad.
But here's a particular case where I just don't know whether behavior is well-defined: a static variable inside a function. Can I rely on the function behaving consistently even during program shutdown? Or is it possible that the static member will be destroyed, and the function will run anyway, without creating a new one?
Here's a toy example demonstrating what I'm interested in:
class Logger
public:
enum class Severity DEBUG, INFO, WARNING, ERROR ;
void Log(Severity sev, const std::string& msg)
LogImpl(FormatMessage(sev, msg));
Logger() Log(Severity::INFO, "Logger active");
~Logger() Log(Severity::INFO, "Logger inactive");
protected:
static std::string FormatMessage(Severity sev, const std::string& msg)
static const std::map<Severity, std::string> enum2str
Severity::DEBUG, "DEBUG",
Severity::INFO, "INFO",
Severity::WARNING, "WARNING",
Severity::ERROR, "ERROR"
;
// Throws or crashes if enum2str is invalid, or uninitialized:
return "[" + enum2str[sev] + "] " + msg;
void LogImpl(const std::string& msg)
std::cout << msg << std::endl;
;
Let's imagine I have a global instance of Logger
. The enum2str
map in Logger::FormatMessage
is a static variable, so at some point during program shutdown, it will be destroyed.
By standard, can this cause my program to crash on shutdown? Is enum2str
inherently unreliable during shutdown? Or is there some handling of this -- for example, if enum2str
is invalid at some point, perhaps a new static instance will be created?
(I am not interested in relying on destruction order between objects, e.g. where I declare the global Logger
instance.)
c++ static destructor
add a comment |Â
up vote
6
down vote
favorite
Quick context: I'm seeing errors on program shutdown, that stem from dependencies between global members (::sigh::, I know, I know). One global variable's destructor might refer to another global -- and if that one's already been destructed, things get bad.
But here's a particular case where I just don't know whether behavior is well-defined: a static variable inside a function. Can I rely on the function behaving consistently even during program shutdown? Or is it possible that the static member will be destroyed, and the function will run anyway, without creating a new one?
Here's a toy example demonstrating what I'm interested in:
class Logger
public:
enum class Severity DEBUG, INFO, WARNING, ERROR ;
void Log(Severity sev, const std::string& msg)
LogImpl(FormatMessage(sev, msg));
Logger() Log(Severity::INFO, "Logger active");
~Logger() Log(Severity::INFO, "Logger inactive");
protected:
static std::string FormatMessage(Severity sev, const std::string& msg)
static const std::map<Severity, std::string> enum2str
Severity::DEBUG, "DEBUG",
Severity::INFO, "INFO",
Severity::WARNING, "WARNING",
Severity::ERROR, "ERROR"
;
// Throws or crashes if enum2str is invalid, or uninitialized:
return "[" + enum2str[sev] + "] " + msg;
void LogImpl(const std::string& msg)
std::cout << msg << std::endl;
;
Let's imagine I have a global instance of Logger
. The enum2str
map in Logger::FormatMessage
is a static variable, so at some point during program shutdown, it will be destroyed.
By standard, can this cause my program to crash on shutdown? Is enum2str
inherently unreliable during shutdown? Or is there some handling of this -- for example, if enum2str
is invalid at some point, perhaps a new static instance will be created?
(I am not interested in relying on destruction order between objects, e.g. where I declare the global Logger
instance.)
c++ static destructor
add a comment |Â
up vote
6
down vote
favorite
up vote
6
down vote
favorite
Quick context: I'm seeing errors on program shutdown, that stem from dependencies between global members (::sigh::, I know, I know). One global variable's destructor might refer to another global -- and if that one's already been destructed, things get bad.
But here's a particular case where I just don't know whether behavior is well-defined: a static variable inside a function. Can I rely on the function behaving consistently even during program shutdown? Or is it possible that the static member will be destroyed, and the function will run anyway, without creating a new one?
Here's a toy example demonstrating what I'm interested in:
class Logger
public:
enum class Severity DEBUG, INFO, WARNING, ERROR ;
void Log(Severity sev, const std::string& msg)
LogImpl(FormatMessage(sev, msg));
Logger() Log(Severity::INFO, "Logger active");
~Logger() Log(Severity::INFO, "Logger inactive");
protected:
static std::string FormatMessage(Severity sev, const std::string& msg)
static const std::map<Severity, std::string> enum2str
Severity::DEBUG, "DEBUG",
Severity::INFO, "INFO",
Severity::WARNING, "WARNING",
Severity::ERROR, "ERROR"
;
// Throws or crashes if enum2str is invalid, or uninitialized:
return "[" + enum2str[sev] + "] " + msg;
void LogImpl(const std::string& msg)
std::cout << msg << std::endl;
;
Let's imagine I have a global instance of Logger
. The enum2str
map in Logger::FormatMessage
is a static variable, so at some point during program shutdown, it will be destroyed.
By standard, can this cause my program to crash on shutdown? Is enum2str
inherently unreliable during shutdown? Or is there some handling of this -- for example, if enum2str
is invalid at some point, perhaps a new static instance will be created?
(I am not interested in relying on destruction order between objects, e.g. where I declare the global Logger
instance.)
c++ static destructor
Quick context: I'm seeing errors on program shutdown, that stem from dependencies between global members (::sigh::, I know, I know). One global variable's destructor might refer to another global -- and if that one's already been destructed, things get bad.
But here's a particular case where I just don't know whether behavior is well-defined: a static variable inside a function. Can I rely on the function behaving consistently even during program shutdown? Or is it possible that the static member will be destroyed, and the function will run anyway, without creating a new one?
Here's a toy example demonstrating what I'm interested in:
class Logger
public:
enum class Severity DEBUG, INFO, WARNING, ERROR ;
void Log(Severity sev, const std::string& msg)
LogImpl(FormatMessage(sev, msg));
Logger() Log(Severity::INFO, "Logger active");
~Logger() Log(Severity::INFO, "Logger inactive");
protected:
static std::string FormatMessage(Severity sev, const std::string& msg)
static const std::map<Severity, std::string> enum2str
Severity::DEBUG, "DEBUG",
Severity::INFO, "INFO",
Severity::WARNING, "WARNING",
Severity::ERROR, "ERROR"
;
// Throws or crashes if enum2str is invalid, or uninitialized:
return "[" + enum2str[sev] + "] " + msg;
void LogImpl(const std::string& msg)
std::cout << msg << std::endl;
;
Let's imagine I have a global instance of Logger
. The enum2str
map in Logger::FormatMessage
is a static variable, so at some point during program shutdown, it will be destroyed.
By standard, can this cause my program to crash on shutdown? Is enum2str
inherently unreliable during shutdown? Or is there some handling of this -- for example, if enum2str
is invalid at some point, perhaps a new static instance will be created?
(I am not interested in relying on destruction order between objects, e.g. where I declare the global Logger
instance.)
c++ static destructor
c++ static destructor
asked 2 hours ago
Ziv
1,25011533
1,25011533
add a comment |Â
add a comment |Â
2 Answers
2
active
oldest
votes
up vote
2
down vote
Without seeing more of your program, the general answer is yes. That destruction of that static map can cause your program to have undefined behavior:
[basic.start.term]
3 If the completion of the constructor or dynamic initialization of an
object with static storage duration strongly happens before that of
another, the completion of the destructor of the second is sequenced
before the initiation of the destructor of the first [...]
4 If a function contains a block-scope object of static or thread
storage duration that has been destroyed and the function is called
during the destruction of an object with static or thread storage
duration, the program has undefined behavior if the flow of control
passes through the definition of the previously destroyed block-scope
object. Likewise, the behavior is undefined if the block-scope object
is used indirectly (i.e., through a pointer) after its destruction.
In general, static objects are destroyed in reverse order to being initialized. So hypothetically, if you have a static object that is initialized early, before the map in the logger, and it logs something in its own destructor, you'll get undefined behavior.
add a comment |Â
up vote
2
down vote
I am not interested in relying on destruction order between objects
You should, since that is exactly what determines whether FormatMessage
is safe to call during the program shutdown.
The code that runs during shutdown is destructors of static objects, and function registered with atExit
.
Can I rely on a function-scoped static variable for a method called during program shutdown?
You cannot rely on it in general, but you can rely on it in certain circumstances.
It is safe to rely on static objects in atExit
, so it is safe to call FormatMessage
there. Unless you can guarantee the order of destruction between particular static object s
, and enum2str
, it is not safe to use FormatMessage
in the destructor of s
.
Static objects are guaranteed to be destroyed in reverse order of their construction. Therefore you can rely on enum2str
existing during destruction of the subset of static objects whose constructors call FormatMessage
, because calling FormatMessage
in the constructor ensures that enum2str
will have been constructed before that dependent static object has finished constructing.
There is a trick to relying on a static object regardless of the order of destruction: Never destruct the dependee. This can be achieved by using a static pointer to a dynamically allocated object, that you intentionally never delete. As a drawback, this will trigger diagnostics in memory analyzers and may increase the blood pressure of your dogmatic co-workers.
add a comment |Â
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
2
down vote
Without seeing more of your program, the general answer is yes. That destruction of that static map can cause your program to have undefined behavior:
[basic.start.term]
3 If the completion of the constructor or dynamic initialization of an
object with static storage duration strongly happens before that of
another, the completion of the destructor of the second is sequenced
before the initiation of the destructor of the first [...]
4 If a function contains a block-scope object of static or thread
storage duration that has been destroyed and the function is called
during the destruction of an object with static or thread storage
duration, the program has undefined behavior if the flow of control
passes through the definition of the previously destroyed block-scope
object. Likewise, the behavior is undefined if the block-scope object
is used indirectly (i.e., through a pointer) after its destruction.
In general, static objects are destroyed in reverse order to being initialized. So hypothetically, if you have a static object that is initialized early, before the map in the logger, and it logs something in its own destructor, you'll get undefined behavior.
add a comment |Â
up vote
2
down vote
Without seeing more of your program, the general answer is yes. That destruction of that static map can cause your program to have undefined behavior:
[basic.start.term]
3 If the completion of the constructor or dynamic initialization of an
object with static storage duration strongly happens before that of
another, the completion of the destructor of the second is sequenced
before the initiation of the destructor of the first [...]
4 If a function contains a block-scope object of static or thread
storage duration that has been destroyed and the function is called
during the destruction of an object with static or thread storage
duration, the program has undefined behavior if the flow of control
passes through the definition of the previously destroyed block-scope
object. Likewise, the behavior is undefined if the block-scope object
is used indirectly (i.e., through a pointer) after its destruction.
In general, static objects are destroyed in reverse order to being initialized. So hypothetically, if you have a static object that is initialized early, before the map in the logger, and it logs something in its own destructor, you'll get undefined behavior.
add a comment |Â
up vote
2
down vote
up vote
2
down vote
Without seeing more of your program, the general answer is yes. That destruction of that static map can cause your program to have undefined behavior:
[basic.start.term]
3 If the completion of the constructor or dynamic initialization of an
object with static storage duration strongly happens before that of
another, the completion of the destructor of the second is sequenced
before the initiation of the destructor of the first [...]
4 If a function contains a block-scope object of static or thread
storage duration that has been destroyed and the function is called
during the destruction of an object with static or thread storage
duration, the program has undefined behavior if the flow of control
passes through the definition of the previously destroyed block-scope
object. Likewise, the behavior is undefined if the block-scope object
is used indirectly (i.e., through a pointer) after its destruction.
In general, static objects are destroyed in reverse order to being initialized. So hypothetically, if you have a static object that is initialized early, before the map in the logger, and it logs something in its own destructor, you'll get undefined behavior.
Without seeing more of your program, the general answer is yes. That destruction of that static map can cause your program to have undefined behavior:
[basic.start.term]
3 If the completion of the constructor or dynamic initialization of an
object with static storage duration strongly happens before that of
another, the completion of the destructor of the second is sequenced
before the initiation of the destructor of the first [...]
4 If a function contains a block-scope object of static or thread
storage duration that has been destroyed and the function is called
during the destruction of an object with static or thread storage
duration, the program has undefined behavior if the flow of control
passes through the definition of the previously destroyed block-scope
object. Likewise, the behavior is undefined if the block-scope object
is used indirectly (i.e., through a pointer) after its destruction.
In general, static objects are destroyed in reverse order to being initialized. So hypothetically, if you have a static object that is initialized early, before the map in the logger, and it logs something in its own destructor, you'll get undefined behavior.
answered 1 hour ago
StoryTeller
86.1k12173240
86.1k12173240
add a comment |Â
add a comment |Â
up vote
2
down vote
I am not interested in relying on destruction order between objects
You should, since that is exactly what determines whether FormatMessage
is safe to call during the program shutdown.
The code that runs during shutdown is destructors of static objects, and function registered with atExit
.
Can I rely on a function-scoped static variable for a method called during program shutdown?
You cannot rely on it in general, but you can rely on it in certain circumstances.
It is safe to rely on static objects in atExit
, so it is safe to call FormatMessage
there. Unless you can guarantee the order of destruction between particular static object s
, and enum2str
, it is not safe to use FormatMessage
in the destructor of s
.
Static objects are guaranteed to be destroyed in reverse order of their construction. Therefore you can rely on enum2str
existing during destruction of the subset of static objects whose constructors call FormatMessage
, because calling FormatMessage
in the constructor ensures that enum2str
will have been constructed before that dependent static object has finished constructing.
There is a trick to relying on a static object regardless of the order of destruction: Never destruct the dependee. This can be achieved by using a static pointer to a dynamically allocated object, that you intentionally never delete. As a drawback, this will trigger diagnostics in memory analyzers and may increase the blood pressure of your dogmatic co-workers.
add a comment |Â
up vote
2
down vote
I am not interested in relying on destruction order between objects
You should, since that is exactly what determines whether FormatMessage
is safe to call during the program shutdown.
The code that runs during shutdown is destructors of static objects, and function registered with atExit
.
Can I rely on a function-scoped static variable for a method called during program shutdown?
You cannot rely on it in general, but you can rely on it in certain circumstances.
It is safe to rely on static objects in atExit
, so it is safe to call FormatMessage
there. Unless you can guarantee the order of destruction between particular static object s
, and enum2str
, it is not safe to use FormatMessage
in the destructor of s
.
Static objects are guaranteed to be destroyed in reverse order of their construction. Therefore you can rely on enum2str
existing during destruction of the subset of static objects whose constructors call FormatMessage
, because calling FormatMessage
in the constructor ensures that enum2str
will have been constructed before that dependent static object has finished constructing.
There is a trick to relying on a static object regardless of the order of destruction: Never destruct the dependee. This can be achieved by using a static pointer to a dynamically allocated object, that you intentionally never delete. As a drawback, this will trigger diagnostics in memory analyzers and may increase the blood pressure of your dogmatic co-workers.
add a comment |Â
up vote
2
down vote
up vote
2
down vote
I am not interested in relying on destruction order between objects
You should, since that is exactly what determines whether FormatMessage
is safe to call during the program shutdown.
The code that runs during shutdown is destructors of static objects, and function registered with atExit
.
Can I rely on a function-scoped static variable for a method called during program shutdown?
You cannot rely on it in general, but you can rely on it in certain circumstances.
It is safe to rely on static objects in atExit
, so it is safe to call FormatMessage
there. Unless you can guarantee the order of destruction between particular static object s
, and enum2str
, it is not safe to use FormatMessage
in the destructor of s
.
Static objects are guaranteed to be destroyed in reverse order of their construction. Therefore you can rely on enum2str
existing during destruction of the subset of static objects whose constructors call FormatMessage
, because calling FormatMessage
in the constructor ensures that enum2str
will have been constructed before that dependent static object has finished constructing.
There is a trick to relying on a static object regardless of the order of destruction: Never destruct the dependee. This can be achieved by using a static pointer to a dynamically allocated object, that you intentionally never delete. As a drawback, this will trigger diagnostics in memory analyzers and may increase the blood pressure of your dogmatic co-workers.
I am not interested in relying on destruction order between objects
You should, since that is exactly what determines whether FormatMessage
is safe to call during the program shutdown.
The code that runs during shutdown is destructors of static objects, and function registered with atExit
.
Can I rely on a function-scoped static variable for a method called during program shutdown?
You cannot rely on it in general, but you can rely on it in certain circumstances.
It is safe to rely on static objects in atExit
, so it is safe to call FormatMessage
there. Unless you can guarantee the order of destruction between particular static object s
, and enum2str
, it is not safe to use FormatMessage
in the destructor of s
.
Static objects are guaranteed to be destroyed in reverse order of their construction. Therefore you can rely on enum2str
existing during destruction of the subset of static objects whose constructors call FormatMessage
, because calling FormatMessage
in the constructor ensures that enum2str
will have been constructed before that dependent static object has finished constructing.
There is a trick to relying on a static object regardless of the order of destruction: Never destruct the dependee. This can be achieved by using a static pointer to a dynamically allocated object, that you intentionally never delete. As a drawback, this will trigger diagnostics in memory analyzers and may increase the blood pressure of your dogmatic co-workers.
edited 1 hour ago
answered 1 hour ago
user2079303
72.2k552110
72.2k552110
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52925392%2fcan-i-rely-on-a-function-scoped-static-variable-for-a-method-called-during-progr%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password