Ваша программа работает правильно (при компиляции в один файл), если вы удалите эту строку:
static volatile S &S_instance = S::instance();
OK. При сборке на моей машине без вашего объявления S_instance:
0000000000400d86 <__static_initialization_and_destruction_0(int, int)>:
400d86: 55 push %rbp
400d87: 48 89 e5 mov %rsp,%rbp
400d8a: 48 83 ec 10 sub $0x10,%rsp
400d8e: 89 7d fc mov %edi,-0x4(%rbp)
400d91: 89 75 f8 mov %esi,-0x8(%rbp)
400d94: 83 7d fc 01 cmpl $0x1,-0x4(%rbp)
400d98: 75 43 jne 400ddd <__static_initialization_and_destruction_0(int, int)+0x57>
400d9a: 81 7d f8 ff ff 00 00 cmpl $0xffff,-0x8(%rbp)
400da1: 75 3a jne 400ddd <__static_initialization_and_destruction_0(int, int)+0x57>
400da3: b8 b8 40 40 00 mov $0x4040b8,%eax
400da8: 0f b6 00 movzbl (%rax),%eax
400dab: 84 c0 test %al,%al
400dad: 75 2e jne 400ddd <__static_initialization_and_destruction_0(int, int)+0x57>
400daf: b8 b8 40 40 00 mov $0x4040b8,%eax
400db4: c6 00 01 movb $0x1,(%rax)
400db7: be 00 00 00 00 mov $0x0,%esi
400dbc: bf b0 40 40 00 mov $0x4040b0,%edi
400dc1: e8 3c 05 00 00 callq 401302 <boost::scoped_ptr<S>::scoped_ptr(S*)>
400dc6: b8 da 13 40 00 mov $0x4013da,%eax
400dcb: ba 90 40 40 00 mov $0x404090,%edx
400dd0: be b0 40 40 00 mov $0x4040b0,%esi
400dd5: 48 89 c7 mov %rax,%rdi
400dd8: e8 8b fd ff ff callq 400b68 <__cxa_atexit@plt>
400ddd: c9 leaveq
400dde: c3 retq
При компиляции с объявлением S_instance:
0000000000400d86 <__static_initialization_and_destruction_0(int, int)>:
400d86: 55 push %rbp
400d87: 48 89 e5 mov %rsp,%rbp
400d8a: 48 83 ec 10 sub $0x10,%rsp
400d8e: 89 7d fc mov %edi,-0x4(%rbp)
400d91: 89 75 f8 mov %esi,-0x8(%rbp)
400d94: 83 7d fc 01 cmpl $0x1,-0x4(%rbp)
400d98: 75 4f jne 400de9 <__static_initialization_and_destruction_0(int, int)+0x63>
400d9a: 81 7d f8 ff ff 00 00 cmpl $0xffff,-0x8(%rbp)
400da1: 75 46 jne 400de9 <__static_initialization_and_destruction_0(int, int)+0x63>
400da3: e8 c2 04 00 00 callq 40126a <Singleton<S>::instance()>
400da8: 48 89 05 01 33 00 00 mov %rax,0x3301(%rip) # 4040b0 <S_instance>
400daf: b8 c0 40 40 00 mov $0x4040c0,%eax
400db4: 0f b6 00 movzbl (%rax),%eax
400db7: 84 c0 test %al,%al
400db9: 75 2e jne 400de9 <__static_initialization_and_destruction_0(int, int)+0x63>
400dbb: b8 c0 40 40 00 mov $0x4040c0,%eax
400dc0: c6 00 01 movb $0x1,(%rax)
400dc3: be 00 00 00 00 mov $0x0,%esi
400dc8: bf b8 40 40 00 mov $0x4040b8,%edi
400dcd: e8 3c 05 00 00 callq 40130e <boost::scoped_ptr<S>::scoped_ptr(S*)>
400dd2: b8 e6 13 40 00 mov $0x4013e6,%eax
400dd7: ba 90 40 40 00 mov $0x404090,%edx
400ddc: be b8 40 40 00 mov $0x4040b8,%esi
400de1: 48 89 c7 mov %rax,%rdi
400de4: e8 7f fd ff ff callq 400b68 <__cxa_atexit@plt>
400de9: c9 leaveq
400dea: c3 retq
В последнем коде вы можете ясно видеть, что конструктор для статического scoped_ptr происходит после S_instance.
Выше были составлены из:
#include <cstdio>
#include <boost/scoped_ptr.hpp>
#include <boost/thread/once.hpp>
#include <boost/noncopyable.hpp>
template <class T> class Singleton : public boost::noncopyable {
public:
static T& instance() {
boost::call_once(init, flag);
return *t;
}
static void init() {
t.reset(new T());
}
private:
static boost::scoped_ptr <T> t;
static boost::once_flag flag;
};
template <class T> boost::scoped_ptr<T> Singleton<T>::t(0);
template <class T> boost::once_flag Singleton<T>::flag = BOOST_ONCE_INIT;
class S : public Singleton<S> {
public:
void p() { printf("hello");}
};
// static volatile S &S_instance = S::instance();
int main()
{
S &ss = S::instance();
ss.p();
}