Order of static destructors - c++

If a class Foo has a static member variable Bar, I would expect Bar's destructor to run only after the last instance of Foo's destructor runs. This doesn't happen with the code snippet below (gcc 6.3, clang 3.8):
#include <memory>
#include <iostream>
class Foo;
static std::unique_ptr<Foo> foo;
struct Bar {
Bar() {
std::cout << "Bar()" << std::endl;
}
~Bar() {
std::cout << "~Bar()" << std::endl;
}
};
struct Foo {
Foo() {
std::cout << "Foo()" << std::endl;
}
~Foo() {
std::cout << "~Foo()" << std::endl;
}
static Bar bar;
};
Bar Foo::bar;
int main(int argc, char **argv) {
foo = std::make_unique<Foo>();
}
Outputs:
Bar()
Foo()
~Bar()
~Foo()
Why is the order of destruction not the reverse of construction here?
If ~Foo() uses Foo::bar this is a use after delete.

In C++ the objects are constructed in order of occurrence and destructed in the reverse order. First comes foo construction, then bar construction then main is executed then bar is destructed and then foo. This is the behavior you are seeing. The switch appears because the constructor of foo doesn't construct a Foo, it constructs an empty unique_ptr, so you don't get to see Foo() in the output. Then bar is constructed with the output and in main you create the actual Foo after foo has long been constructed.

I would expect Bar's destructor to run only after the last instance of Foo's destructor runs.
No, as a static data member, Foo::bar is independent of any instances of Foo.
And for the code you showed,
static std::unique_ptr<Foo> foo; // no Foo created here
Bar Foo::bar; // Foo::bar is initialized before main(), => "Bar()"
int main(int argc, char **argv) {
foo = std::make_unique<Foo>(); // an instance of Foo is created, => "Foo()"
}
// objects are destroyed in the reverse order how they're declared
// Foo::bar is defined after foo, so it's destroyed at first => "~Bar()"
// foo is destroyed; the instance of Foo managed by it is destroyed too => "~Foo()"

The complication here is that the code doesn’t instrument the constructor of foo. What happens is that foo gets constructed first, than Foo::bar gets constructed. The call to make…unique constructs a Foo object. Then main exits, and the two static objects get destroyed in reverse order of their construction: Foo::bar gets destroyed, then foo. The destructor for foo destroys the Foo object that it points to, which is the one created inmain.

Static objects' lifetimes are based solely on the order of their definition. The compiler doesn't "know enough" when to call Bar::Bar() as much as calling Bar::~Bar().
To illustrate the problem better, consider this
class Foo;
struct Bar {
Bar() {
std::cout << "Bar()" << std::endl;
}
~Bar() {
std::cout << "~Bar()" << std::endl;
}
void baz() {}
};
struct Foo {
Foo() {
bar.baz();
std::cout << "Foo()" << std::endl;
}
~Foo() {
std::cout << "~Foo()" << std::endl;
}
static Bar bar;
};
Foo foo;
Bar Foo::bar;
int main() {}
Prints
Foo()
Bar()
~Bar()
~Foo()
The addition of std::unique_ptr postpones Foo::Foo() after its construction in main, giving the illusion of the compiler "knowing" when to call Bar::Bar().
TLDR Static objects should be defined later than its dependencies. Before defining bar, it is just as much a bug to define a std::unique_ptr<Foo> and to define a Foo

In general, you should not write code which depends on the order of construction or destruction of static (or global) data. This makes unreadable and unmaintainable code (you might prefer static smart pointers, or
explicit initialization or startup routines called from main). And AFAIK that order is not specified when you link several translation units.
Notice that GCC provides the init_priority and constructor (with priority) attributes. I believe you should rather avoid using them. However, the __attribute__(constructor) is useful inside plugins, for plugin initialization.
In some cases, you might also use atexit(3) (at least on POSIX systems). I don't know if such registered functions are called before or after destructors (and I think you should not care about that order).

Related

Why does the compiler create a variable that's only used once?

Consider the following two examples, both compiled with g++ (GCC) 12.1.0 targetting x86_64-pc-linux-gnu: g++ -O3 -std=gnu++20 main.cpp.
Example 1:
#include <iostream>
class Foo {
public:
Foo(){ std::cout << "Foo constructor" << std::endl;}
Foo(Foo&& f) { std::cout << "Foo move constructor" << std::endl;}
Foo(const Foo& f) {std::cout << "Foo copy constructor" << std::endl;}
~Foo() { std::cout << "Foo destructor" << std::endl;}
};
class Baz {
private:
Foo foo;
public:
Baz(Foo foo) : foo(std::move(foo)) {}
~Baz() { std::cout << "Baz destructor" << std::endl;}
};
Foo bar() {
return Foo();
}
int main() {
Baz baz(bar());
return 0;
}
Output:
Foo constructor
Foo move constructor
Foo destructor
Baz destructor
Foo destructor
Example 2:
#include <iostream>
class Foo {
public:
Foo(){ std::cout << "Foo constructor" << std::endl;}
Foo(Foo&& f) { std::cout << "Foo move constructor" << std::endl;}
Foo(const Foo& f) {std::cout << "Foo copy constructor" << std::endl;}
~Foo() { std::cout << "Foo destructor" << std::endl;}
};
class Baz {
private:
Foo foo;
public:
Baz(Foo foo) : foo(std::move(foo)) {}
~Baz() { std::cout << "Baz destructor" << std::endl;}
};
Foo bar() {
return Foo();
}
int main() {
// DIFFERENCE IS RIGHT HERE
Foo f = bar();
Baz baz(f);
return 0;
}
Output:
Foo constructor
Foo copy constructor
Foo move constructor
Foo destructor
Baz destructor
Foo destructor
Foo destructor
So the difference here is that there is an additional instance of Foo, which needs to be handled. I find this difference quite shocking, as my (apparently untrained) eyes would not even consider these pieces of code effectively different. Moreover, a collegue might ask me to turn example 1 into example 2 for readability and suddenly I will be incurring a performance penalty!
So why are example 1 and 2 so different according to the compiler/C++ spec that the resulting code suddenly needs to copy? Why can the compiler not generate the same code for both cases?
In
Foo f = bar();
Baz baz(f);
return 0
It is indeed obvious that f will never be used again and the compiler probably even works this out. However the compiler isn't allowed to move f into baz, all optimisations done by the compiler must result in your program having the same behaviour (if the program is well defined to start with). Especially in your case where the move and copy constructors print different things, making this optimisation would change the behaviour of your program. In a more realistic program the compiler may be able to deduce that the code would have the same behaviour with a move or a copy and change a copy into a move but it's always best to give the compiler as much help as possible and not rely on it making optimisations.
If you know that you don't need f any more then you can tell the compiler this by converting it to an rvalue reference using std::move, then it will use the move constructor (if available):
Foo f = bar();
Baz baz(std::move(f));
return 0
why are example 1 and 2 so different according to the compiler/C++ spec that the resulting code suddenly needs to copy?
Because in example 2 you have a variable named f of type Foo which is used to initialize baz while in example 1 you're initializing baz with a prvalue of type Foo which will result in directly constructing the parameter foo and then moving from it.
To be more precise, in example 2 since f in the statement Baz baz(f); is an lvalue expression and so the copy ctor Foo::Foo(const Foo&) will be used to initialize the parameter Foo foo of the converting ctor Baz::Baz(Foo). Thus we get the output corresponding to the copy ctor. Next due to foo(std::move(foo)) we will also get a call to the move ctor.
While in example 1, bar() is a prvalue of type Foo. This means that the parameter Foo foo of Baz::Baz(Foo) will be directly constructed(due to mandatory copy elison in C++17) and then due to foo(std::move(foo)) we also get a call to the move ctor.
Let's see step by step explanation.
Case 1
Here we consider example:
Baz baz(bar());
Step 1: The parameterized ctor Baz::Baz(Foo foo) will be used here.
Step 2: Since bar() is a prvalue, the parameter named foo of the parameterized ctor Baz::Baz(Foo foo) will be directly constructed due to mandatory copy elison in C++17. Thus we get the first statement of the output Foo constructor.
Step 3 Now due to foo(std::move(foo)) we get the call to the move ctor Foo::Foo(Foo&& f) and so the second statement of the output Foo move constructor.
Case 2
Here we consider:
Foo f = bar(); //this will call the default ctor and so we get the first statement of the output
//------v------->f is an lvalue
Baz baz(f);
Step 1 Here also the parameterized ctor Baz::Baz(Foo foo) will be used.
Step 2 But this time since f is an lvalue expression the copy ctor Foo::Foo(const Foo&) will be used to initialized the parameter named foo of the parameterized ctor Baz::Baz(Foo foo). Thus we get the second statement of the output Foo copy constructor.
Step 3 Next due to foo(std::move(foo)) we get a call to the move ctor and the third statement of the output Foo move constructor

Override delete operator with empty implementation

Using the delete operator on an object normally leads to two things: calling the object's destructor (and its virtual base destructors, if present) and freeing the memory afterwards.
If override the delete operator on a class giving it an empty implementation {}, the destructor will still be called, but the memory does not get freed.
Assuming the destructor is also empty, will the delete then have any effect or would it be safe to continue using the "deleted" object (i.e. is there undefined behaviour)?
struct Foo {
static void operator delete(void* ptr) {}
Foo() {}
~Foo() {}
void doSomething() { ... }
}
int main() {
Foo* foo = new Foo();
delete foo;
foo->doSomething(); // safe?
}
Not that this would make much sense as it is, but I'm investigating in a "deferred delete" (gc) mechanism where objects won't get deleted instantly when delete gets called but shortly afterwards.
Update
Referring to some answers that mention memory leaks: let's assume the overloaded delete operator is not empty, but does store its ptr argument in a (let's say static, for the sake of simplicity) set:
struct Foo {
static std::unordered_set<void*> deletedFoos;
static void operator delete(void* ptr) {
deletedFoos.insert(ptr);
}
Foo() {}
~Foo() {}
}
And this set gets cleaned up periodically:
for (void* ptr : Foo::deletedFoos) {
::operator delete(ptr);
}
Foo::deletedFoos.clear();
From n4296:
A destructor is invoked implicitly
(11.1) — for a constructed object with static storage duration (3.7.1)
at program termination (3.6.3),
(11.2) — for a constructed object with thread storage duration (3.7.2)
at thread exit,
(11.3) — for a constructed object with automatic storage duration
(3.7.3) when the block in which an object is created exits (6.7),
(11.4) — for a constructed temporary object when its lifetime ends
(12.2).
In each case, the context of the invocation is the context of the
construction of the object. A destructor is also invoked implicitly
through use of a delete-expression (5.3.5) for a constructed object
allocated by a new-expression (5.3.4); the context of the invocation
is the delete-expression. [ Note: An array of class type contains
several subobjects for each of which the destructor is invoked. —end
note ] A destructor can also be invoked explicitly.
Thus, the very use of delete expression that calls delete operator, you implicitly call destructor as well. Object's life ended, it's an undefined behavior what happens if you will call a method for that object.
#include <iostream>
struct Foo {
static void operator delete(void* ptr) {}
Foo() {}
~Foo() { std::cout << "Destructor called\n"; }
void doSomething() { std::cout << __PRETTY_FUNCTION__ << " called\n"; }
};
int main() {
Foo* foo = new Foo();
delete foo;
foo->doSomething();
// safe? No, an UB. Object's life is ended by delete expression.
}
Output:
Destructor called
void Foo::doSomething() called
used: gcc HEAD 8.0.0 20170809 with -O2
The question starts with assumption that redefining delete operator and behaviour of object would omit destruction of object. Redefining destructor of object itself will not redefine destructors of its fields.
In fact it won't exist anymore from semantics point of view. It will not deallocate memory, which might be a thing if object is stored in memory pool. But it would delete abstract 'soul' of object, so to say. Calling methods or accessing fields of object after that is UB.
In particular case, depending on operation system, that memory may stay forever allocated. Which is an unsafe behavior. It also unsafe to assume that compiler would generate sensible code. It may omit actions altogether.
Let me add some data to object:
struct Foo {
int a;
static void operator delete(void* ptr) {}
Foo(): a(5) {}
~Foo() { std::cout << "Destructor called\n"; }
void doSomething() { std::cout << __PRETTY_FUNCTION__ << "a = " << a << " called\n"; }
};
int main() {
Foo* foo = new Foo();
delete foo;
foo->doSomething(); // safe?
}
Output:
Destructor called
void Foo::doSomething() a= 566406056 called
Hm? We didn't initialized memory? Let's add same call before destruction.
int main() {
Foo* foo = new Foo();
foo->doSomething(); // safe!
delete foo;
foo->doSomething(); // safe?
}
Output here:
void Foo::doSomething() a= 5 called
Destructor called
void Foo::doSomething() a= 5 called
What? Of course, compiler just omitted initialization of a in first case. Could it be because class doesn't do anything else? In this case it is possible. But this:
struct Foo {
int a, b;
static void operator delete(void* ptr) {}
Foo(): a(5), b(10) {}
~Foo() { std::cout << "Destructor called\n"; }
void doSomething() { std::cout << __PRETTY_FUNCTION__ << " a= " << a << " called\n"; }
};
int main() {
Foo* foo = new Foo();
std::cout << __PRETTY_FUNCTION__ << " b= " << foo->b << "\n";
delete foo;
foo->doSomething(); // safe?
}
will generate similar undefined value:
int main() b= 10
Destructor called
void Foo::doSomething() a= 2017741736 called
Compiler had considered field a unused by the time of death of foo and thus "dead" without impact on further code. foo went down with all "hands" and none of them formally do exist anymore. Not to mention that on Windows, using MS compiler those programs would likely crash when Foo::doSomething() would try to revive the dead member. Placement new would allow us to play Dr.Frankenstein role:
#include <iostream>
#include <new>
struct Foo {
int a;
static void operator delete(void* ptr) {}
Foo() {std::cout << __PRETTY_FUNCTION__ << " a= " << a << " called\n"; }
Foo(int _a): a(_a) {std::cout << __PRETTY_FUNCTION__ << " a= " << a << " called\n"; }
~Foo() { std::cout << "Destructor called\n"; }
void doSomething() { std::cout << __PRETTY_FUNCTION__ << " a= " << a << " called\n"; }
};
int main() {
Foo* foo = new Foo(5);
foo->~Foo();
Foo *revenant = new(foo) Foo();
revenant->doSomething();
}
Output:
Foo::Foo(int) a= 5 called
Destructor called
Foo::Foo() a= 1873730472 called
void Foo::doSomething() a= 1873730472 called
Irregardless to wit if we call destructor or not, compilers are allowed to decide that revenant isn't same thing as original object, so we can't reuse old data, only allocated memory.
Curiously enough, while still performing UB, if we remove delete operator from Foo, that operation seem to work as expected with GCC. We do not call delete in this case, yet removal and addition of it changes compiler behavior, which, I believe, is an artifact of implementation.
From N4296 (~C++14):
3.8 Object lifetime [basic.life]
...
The lifetime of an object of type T ends when:
(1.3) — if T is a class type with a non-trivial destructor (12.4), the destructor call starts, or
(1.4) — the storage which the object occupies is reused or released.
Then:
12.4 Destructors [class.dtor]
...
A destructor is trivial if it is not user-provided and if:
(5.4) — the destructor is not virtual,
(5.5) — all of the direct base classes of its class have trivial destructors, and
(5.6) — for all of the non-static data members of its class that are of class type (or array thereof), each such class has a trivial destructor.
Otherwise, the destructor is non-trivial.
So basically, for simple enough classes, this is safe, but if you have any kind of resource-owning classes involved it is not going to be legal.
Take care, though, that in your example your destructor is user-provided, hence non-trivial.
Whether your hack can work depends on the members of the class. The destructor will always call the destructors of the class members. If you have any members that are strings, vectors, or other objects with an 'active' destructor, these objects will be destroyed, even tough the memory allocated for the containing object is still allocated.
The main problem is that even if have empty dtor's, other background things, like the release of virtual method tables, will happen. My personal approach in such cases is to make a private dtor and use a member method (name it destroy if you want) for filtering the delete operator. For example
class A
{
bool _may_be_deleted;
public:
A(bool may_be_deleted)
: _may_be_deleted(may_be_deleted){;}
void allow_delete()
{
_prevent_delete = false;
}
static bool destroy(A*);
private:
virtual ~A(){;}
};
bool A::destroy(A *pA)
{
if(pA->_may_be_deleted)
{
delete pA;
return true;
}
return false;
}
int main(int argc, char* argv[])
{
A* pA = new A(false);
A::destroy(pA); //returns false and A is not deleted
pA->allow_delete();
A::destroy(pA); //Ok, now A is destroyed and returns true;
}
Hope that helps.

Reference or shared_ptr as member for association

I'm writing a class Bar. Bar needs to access an other class Foo to be useful.
So the instance of Foo has to outlive the instance of Bar using it.
I can't decide between two ways to write this. Here is an example:
#include <iostream>
#include <memory>
using namespace std;
struct Foo {
Foo(int _x) : x_(_x) {}
~Foo() {}
int x_;
};
struct Bar1 {
Bar1(Foo& _foo) : foo_(_foo) {}
void print_foo() {cout << foo_.x_ << endl;}
private:
Foo& foo_;
};
struct Bar2 {
Bar2(shared_ptr<Foo> _foo) : foo_{move(_foo)} {}
void print_foo() {cout << foo_->x_ << std::endl;}
private:
shared_ptr<Foo> foo_;
};
int main()
{
Foo f1{1};
shared_ptr<Foo> f2 = make_shared<Foo>(2);
Bar1 b1(f1);
b1.print_foo();
Bar2 b2(f2);
b2.print_foo();
return 0;
}
I think, that Bar1 gives the user more freedom on how to manage the lifetime of Foo
and it probably is more efficient. But it goes in an undefined (not sure if
this is the right word here) state, when the instance of Foo to which foo_ refers is destroyed.
What is the preferred way to handle a situation like this and why?
I think the preferred way to handle this situation depends on the specifics of the situation. As you identified, Bar1 gives the user more freedom with the lifetime of Foo, and is more dangerous. It is also more efficient (slightly), but probably not enough to be a concern.
If you know for a fact (and/or can prove) that Foo will always outlive all of your Bar objects (maybe you allocate the Foo you use on the stack in main), there is no problem using Bar1. If you are unsure, Bar2 would be the way to go. Though the semantics may be wrong with Bar2 (maybe you don't want Bar to keep your Foo alive).
This leads us to a third option: weak_ptr. This would give the user control of the lifetime of Foo, but still allow Bar to have defined behavior when the Foo is destroyed.
struct Bar3 {
Bar3(std::weak_ptr<Foo> _foo) : foo_(_foo) {}
void print_foo_v1() {
// throws if foo_'s object has been destroyed
std::shared_ptr<Foo> foo(foo_);
std::cout << foo->x_ << std::endl;
}
void print_foo_v2() {
// returns nullptr if foo_'s object has been destroyed
std::shared_ptr<Foo> foo(foo_.lock());
if (foo) {
std::cout << foo->x_ << std::endl;
}
}
private:
std::weak_ptr<Foo> foo_;
};
If you know that Foo will outlive Bar use reference-based solution because of simplicity and because it expresses what you want to achieve - that Bar references Foo. If you use pointers then the intent is not that clear.

Virtual function calling a non-virtual function

I wrote the following piece of code to test my understanding of virtual inheritance. Apparently, I still don't get it fully. Here is my code (followed by my question):
#include <iostream>
#include <vector>
using namespace std;
class Foo
{
public:
virtual void foo();
void foo2();
};
void Foo::foo()
{
cout << "In FOO - foo 1" << endl;
foo2();
}
void Foo::foo2()
{
cout << "In FOO - foo 2" << endl;
}
class Bar : public Foo
{
public:
void foo();
void foo2();
};
void Bar::foo()
{
cout << "In BAR - foo 1" << endl;
foo2();
}
void Bar::foo2()
{
cout << "In BAR - foo 2" << endl;
}
int main()
{
Foo* f = new Foo;
f->foo();
Foo* b = new Bar;
b->foo();
return 0;
}
This is my understanding:
The pointer f points to the base class Foo and f->foo() calls foo() in the base class which in turn calls foo2() in the base class.
The pointer b is a base-class pointer but points to an object of the derived class Bar. Now, since foo() is a virtual function, it calls foo() of the derived class. Now foo() (of the derived class) calls foo2(). Since foo2() is not a virtual function, I was expecting the base class foo2() to get called. However I see that foo2() of the derived class is getting called.
So, I was expecting this output:
In FOO - foo 1
In FOO - foo 2
In BAR - foo 1
In FOO - foo 2
but got this instead:
In FOO - foo 1
In FOO - foo 2
In BAR - foo 1
In BAR - foo 2
Why is this so? From what I understand, the vtable will have an entry only for foo() and not for foo2(). So, how is foo2() of the derived class getting called?
This is my first post. Please excuse me if I have broken any posting guidelines. Thanks in advance!
In Bar::foo(), you are calling foo2(). This is really equivalent to calling this->foo2(). The type of this is Bar, so this is really equivalent to:
void Bar::foo()
{
Bar *bar = this;
bar->foo2();
}
So there's no polymorphism involved at this point; the call is resolved to Bar::foo2 at compile-time, rather than dynamically at run-time.
because Bars foo is what's calling foo2, at that stage it knows its a Bar....
try again, except call foo2 directly in main for both rather than foo calling foo2
int main()
{
Foo* f = new Foo;
f->foo();
f->foo2();
Foo* b = new Bar;
b->foo();
b->foo2();
return 0;
}
how is foo2() of the derived class getting called?
You expect Bar::foo2 to never be called. Then your question can be reformulated as: "why is the purpose of Bar::foo2, if any?"
Its purpose is to be called when dealing with Bar objects. The foo2 of a Bar object is called whenever foo2 is called.
It is only for foo objects that it matters whether Foo::bar2 is virtual or not. Inheritance never forces you to use the functions with the same signature in the base class, if you are dealing directly with derived class objects. (It would cause too many unpleasant surprises to have the inheritance rules work differently in this matter.)
What you have essentially done is hiding. By creating a function with the same signature in Bar, you have hidden the nonvirtual function in the base class Foo. This is typically a bad design because it is unnecessarily complex - it is better to choose different names for different things, to avoid hiding. Hiding is seldom part of a conscious good design.
void Bar::foo()
{
cout << "In BAR - foo 1" << endl;
foo2();
}
This is because Bar::foo2() is the foo2() called by foo(). Bar::foo2() is local to Bar::foo() and has precedence. It's just static dispatch from Bar::foo2().
If the behavior you expected is what you really want, you can choose the method by specifying its scope like so:
void Bar::foo()
{
cout << "In BAR - foo 1" << endl;
Foo::foo2();
}
So this really does not have to do with dynamic dispatch.

Will a class recall its constructor when pushed in a std::vector?

if for example I do:
FOO foo;
foovect.push_back(foo);
where FOO is a class with a default constructor.
Will the constructor be called only when foo is put on the stack, or is it called again when pushed into the std::vector?
Thanks
I'm doing:
OGLSHAPE::OGLSHAPE(void)
{
glGenBuffersARB(GL_ARRAY_BUFFER_ARB,&ObjectVBOInt);
}
FOO foo; would call the constructor.
foovect.push_back(foo); would call the copy constructor.
#include <iostream>
#include <vector>
class FOO
{
public:
FOO()
{
std::cout << "Constructor" << std::endl;
}
FOO(const FOO& _f)
{
std::cout << "Copy Constructor" << std::endl;
}
};
int main()
{
FOO foo;
std::vector<FOO> foovect;
foovect.push_back(foo);
}
Output for this:
Constructor
Copy Constructor
No, the copy constructor is used, i.e. the one that looks like this:
FOO( const FOO & f );
A default copy constructor is provided by the compiler, if you don't provide one yourself.
When you do a push_back, your object is copied into the vector. That means the copy constructor for your object gets called. All the standard library containers deal with copies of objects, not the object themselves. If you want that behavior, you'll need to resort to using pointers.