Index: include/ios =================================================================== --- include/ios +++ include/ios @@ -423,13 +423,30 @@ virtual ~failure() throw(); }; +class __shared_count; + class _LIBCPP_TYPE_VIS ios_base::Init { +private: + static __shared_count *UseCount; public: Init(); ~Init(); }; +#ifndef __APPLE__ +// Apple linker has a guarantee for an initialization order: +// if A links against B, B's initializer will be run before A's. +// I.e. if you link to libc++.dylib, then cout et al. are guaranteed +// to be constructed before your initializers run. This way, definition +// of __start_std_streams might remain in src/iostream.cpp, and linker arranges +// its initialization before any stream usage. +// Without Apple linker, that definition must be here, +// so its initialization will be explicitly executed before any stream usage. +// For construction of cout, cin, cerr etc. +static ios_base::Init __start_std_streams; +#endif + // fmtflags inline _LIBCPP_INLINE_VISIBILITY Index: src/iostream.cpp =================================================================== --- src/iostream.cpp +++ src/iostream.cpp @@ -10,6 +10,8 @@ #include "__std_stream" #include "string" #include "new" +#include "cassert" +#include "memory" _LIBCPP_BEGIN_NAMESPACE_STD @@ -41,9 +43,7 @@ _ALIGNAS_TYPE (ostream) _LIBCPP_FUNC_VIS char clog[sizeof(ostream)]; _ALIGNAS_TYPE (wostream) _LIBCPP_FUNC_VIS char wclog[sizeof(wostream)]; -ios_base::Init __start_std_streams; - -ios_base::Init::Init() +static void init_std_streams() { #ifndef _LIBCPP_HAS_NO_STDIN istream* cin_ptr = ::new(cin) istream(::new(__cin) __stdinbuf (stdin, &mb_cin)); @@ -70,7 +70,7 @@ #endif } -ios_base::Init::~Init() +static void fini_std_streams() { #ifndef _LIBCPP_HAS_NO_STDOUT ostream* cout_ptr = reinterpret_cast(cout); @@ -85,4 +85,51 @@ wclog_ptr->flush(); } +/// __Init is a utility class that counts the number of ios_base::Init +/// objects. It automatically deinitializes the std streams when the +/// last ios_base::Init object is destroyed. +class __Init: public __shared_count { +private: + void __on_zero_shared() _NOEXCEPT { + fini_std_streams(); + } +public: + __Init(long count = 0): __shared_count(count) { + init_std_streams(); + } +}; + +_ALIGNAS_TYPE (__Init) _LIBCPP_FUNC_VIS static char __init_storage[sizeof(__Init)]; + +__shared_count *ios_base::Init::UseCount = nullptr; + +ios_base::Init::Init() +{ + //local static object is initialized only once + struct __S { + __S() { + Init::UseCount = ::new(__init_storage) __Init(-1); + } + }; + static __S __s; + UseCount->__add_shared(); +} + +ios_base::Init::~Init() +{ + assert(UseCount); + UseCount->__release_shared(); +} + +#ifdef __APPLE__ +// Apple linker has a guarantee for an initialization order: +// if A links against B, B's initializer will be run before A's. +// I.e. if you link to libc++.dylib, then cout et al. are guaranteed +// to be constructed before your initializers run. This way, initialization +// of __start_std_streams might remain here in module initializer +// Without Apple linker, the following definition must be in header , +// so its initialization will be explicitly executed before any stream usage. +ios_base::Init __start_std_streams; +#endif + _LIBCPP_END_NAMESPACE_STD