0

There is a great FAQ(isocpp) just demonstrates why we potentaily cannot we use static object instead of static pointer to avoid Fiasco problem. I came across a sentence in the answer that gave me a headache

.... By changing the declaration from static X* xp = new X(); to static X xp;, we still correctly handle the initialization situation but we no longer handle the deinitialization situation. For example, if there are 3 static objects, say a, b and c, that use ans during their destructors, the only way to avoid a static deinitialization disaster is if xp is destructed after all three.

main.cpp

#include "x.h" // struct X { X(int); void f(); };

X& x(int i) 
{  
  static X xp{ i }; 
  return xp; 
}
struct Y 
{ 
  Y(int); 
  private: int m_y; 
};
Y::Y(int i) { 
  x(i).f(); 
}

other.cpp

Y y{ 20 };

struct X { 
    X(int); 
    void f(); 
    private: int m_x; 
};
X::X(int j): m_x(j) {};

void X::f() { std::cout << m_x << std::endl; }

Then they continue with:

The point is simple: if there are any other static objects whose destructors might use xp after xp is destructed, bang, you’re dead.

I just cannot understand how this problem can happen. I need a practical example that demonstrates how this problem can occur.

mada
  • 1,646
  • 1
  • 15
  • By definition, it is hard to provide a reproducible case of UB, as the exact results depends on the compile/linker. Can you alter the question to include the environment you are using? – Tiger4Hire Dec 08 '21 at 12:40
  • The link to FAQ(isocpp) seems to be broken? – Christian Halaszovich Dec 08 '21 at 12:40
  • By using new the object never gets destructed since there is no matching delete call anywhere in the code. Which means the object "survives" in memory until the program terminates and its destructor gets never called. Still not what I'd want though. – Pepijn Kramer Dec 08 '21 at 13:06
  • This might also be an interesting read for you : https://stackoverflow.com/questions/40242063/destruction-order-of-meyers-singletons – Pepijn Kramer Dec 08 '21 at 13:07
  • Add `Y::~Y() {x(5).f();}` and now you've got a problem if the Y object gets destroyed after the X object has been destroyed :) – Jeremy Friesner Dec 08 '21 at 15:29
  • 1
    @JeremyFriesner, Can you answer the question? I can't get the destruction order in your case. if I made this `Y::~Y() {x(5).f();}` Now which object is destroyed first?. I already know the destruction order is the inverse of the construction but I can't map this with my example. – mada Dec 08 '21 at 15:49
  • @AccessDenied that's the problem -- destruction order of static-objects across compilation units isn't well-defined; it could happen in one order on one compiler, and a different order on another compiler. Or in one order on Monday, and a different order on Tuesday. You can't rely on any particular order being chosen. – Jeremy Friesner Dec 08 '21 at 15:57
  • 1
    Excuse me, bro. If I have, `Y::~Y() { auto xo = x(100) ; xo.f(); };`, Now the scope of `xo` ends once the control exits `Y::~Y()` and You said: "I will get a problem if object Y gets destroyed after object X which is `xo`" and that's not happening here, `xo` not yet destroyed, so where's the problem? – mada Dec 08 '21 at 16:28
  • 1
    `x()` is returning a reference to the static object `xp`. If `xp` has already been destroyed, then the returned reference is a reference-to-an-invalid object, and any attempt to use that reference invokes undefined behavior. If (on your system, using your current compiler and current build settings) `xp` is getting destroyed after `~Y()` is called rather than before, that's just your luck (good or bad, depending on how you look at it); there's no guarantee it will happen in the same order on another system/compiler/day-of-the-week. – Jeremy Friesner Dec 08 '21 at 21:41
  • 1
    @JeremyFriesner. Great clarification, thanks bro I got it – mada Dec 10 '21 at 13:18

0 Answers0