3

Given this whittled down version of my code:

#include <iostream>

using namespace std;

struct S {
  S( ostream &os ) : os_( os ) { }
  ~S() { os_ << "The end.\n"; }         // line 7
  ostream &os_;
};

void f() {
  static S s( cout );
  (void)s;
}

int main() {
  f();
  return 0;
}

The program prints The end. However, as part of a larger program, it SEGFAULTS while attempting to write to the ostream.

I'm trying to ensure that some text will always get printed at program termination. Is what I'm trying to do legal using iostreams? Would it be better to use atexit(3)?

I thought that because cout was constructed before my using it, that it would be destroyed after; so it's not clear why code like the above should't always work.

Update

If I change line 7 to write to cout directly rather than via the reference, it works fine. That's even more bizarre.

Paul J. Lucas
  • 6,895
  • 6
  • 44
  • 88
  • 2
    Holding a reference to an object that you don't control the lifetime of seems like a bad idea to me. – Jonathan Potter Feb 22 '14 at 01:02
  • @JonathanPotter `std::cout` is static just like the instance of `S` is, which is the reason why he's asking about the behavior. – David G Feb 22 '14 at 01:03
  • 2
    There's no defined order in which static objects are created and destroyed, so you can't depend on `cout` being around when another static object is destroyed. – Gort the Robot Feb 22 '14 at 01:08
  • What?? I thought destruction of static objects is always done in reverse order of construction. – Paul J. Lucas Feb 22 '14 at 01:10
  • @PaulJ.Lucas I believe that only refers to objects with automatic storage duration. – David G Feb 22 '14 at 01:10
  • Also, I think you're getting the correct output when you write to `std::cout` directly is because your program has Undefined Behavior somehow. – David G Feb 22 '14 at 01:12
  • You probably want to check this answer: http://stackoverflow.com/questions/469597/destruction-order-of-static-objects-in-c – Gort the Robot Feb 22 '14 at 04:14
  • So if `cout` is constructed before first use and its first use is trigged by passing it by reference, that means it's constructed before `s`. That being the case, why isn't `cout` always destroyed after `s`? – Paul J. Lucas Feb 22 '14 at 06:55
  • 1
    I'm not sure what the standard says about this, but I know that some compilers don't consider passing a reference as 'first use.' The object has to actually be accessed. gcc is the biggest offender, though I'm not sure about latest versions. – Collin Dauphinee Feb 22 '14 at 08:17
  • Even if I add `os_ << "The beginning.\n"` in the constructor (which _has_ to be considered "first use"), it still crashes. – Paul J. Lucas Feb 22 '14 at 15:01

1 Answers1

0

If you call atexit() after the construction of the static object then the static object will be destroyed after the call to that object. So yes using atexit() should resolve the problem.

See Order between destruction of global object and atexit in C++

Community
  • 1
  • 1
Curious
  • 20,870
  • 8
  • 61
  • 146