为什么在单例实现中清除boost::scopedptr
why boost::scoped_ptr is cleared in a singleton implementation
我使用boost::scoped_ptr:实现了一个简单的单例
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");}
};
然后我在文件S.cpp:中定义了一个静态变量
static volatile S &S_instance = S::instance();
在main.cpp:中
int main()
{
S &ss = S::instance();
ss.p();
}
运行此程序,出现异常:
/usr/include/boost/smart_ptr/scoped_ptr.hpp:91:T&boost::scoped_ptr::operator*()const[带T=S]:断言`px!=0'失败
跟踪代码,我发现一旦代码离开静态初始化段,静态s_instance.t就会被清除,之后所有引用s::实例的代码都会得到NULL scope_ptr。有人知道原因吗?
[更新]我试图将所有静态文件放入一个cpp文件(S1.cpp):
template <class T> boost::scoped_ptr<T> Singleton<T>::t(0);
template <class T> boost::once_flag Singleton<T>::flag = BOOST_ONCE_INIT;
static S& s_ins = S::instance();
并用GDB调试它,它看起来遵循我写的顺序。知道吗?
一个可能的原因是静态template <class T> boost::scoped_ptr<T> Singleton<T>::t(0);
在static volatile S &S_instance = S::instance();
之后被初始化,因此它用0替换了先前存储在t
中的值。静态变量的构造顺序只在一个编译单元中定义,我猜在您的情况下,t
可以在main.cpp
中实例化(或者更确切地说,在编译时在两个文件中实例化,链接器只需要选择一个),而S
位于S.cpp
中。不过只是猜测。
我很确定这是未定义的行为,因为全局变量的创建顺序未定义。因此,首先初始化S_instance
,然后初始化template <class T> boost::scoped_ptr<T> Singleton<T>::t(0)
这样一个简单的程序可以说明,当订单颠倒时会发生什么:
#include <iostream>
std::string &getS();
std::string& t = getS();
std::string s("hello");
std::string &getS() {s = "world"; return s;}
int main()
{
std::cout << t;
}
好吧,它用g++
崩溃了,用cl
打印hello
如果删除以下行,程序将正常工作(当编译为单个文件时):
static volatile S &S_instance = S::instance();
好的。当在我的机器上构建而没有您的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
在后一段代码中,您可以清楚地看到静态scope_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();
}
我认为这是错误的:
static volatile S &S_instance = S::instance();
因为它创建然后删除实例。您需要的是指针,而不是引用。
static S *S_instance = &S::instance();
据我所知,该引用在.cpp文件末尾超出了作用域。无论如何都不希望删除该实例,因此T可以只是一个空指针。
- 理解boost::asio-async_read在无需读取内容时的行为
- boost::进程间消息队列引发错误
- 如何运行位于boost/libs/python/example/tutorial目录中的hello.cpp和Jamfil
- cmake如何在fedora工作站中找到boost静态库包
- CMake项目Boost库错误:Boost/config/compiler/gcc.hpp:165:10:致命错误:cs
- Boost Graph Library,修复节点大小
- 什么是"#include <boost/functional/hash.hpp> "?
- 基于boost的程序的静态链接——zlib问题
- C++:如何在CLion IDE中安装Boost
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- 如何在boost beast http请求中设置http头
- Boost Spirit,获取迭代器内部语义动作
- boost::asio::steady_timer()与sleep()我应该使用哪一个
- boost::asio如何生成多个协同程序,然后加入它们
- 当我尝试使用 sstream 和分面将 Boost Time_duration转换为字符串时,我没有得到所需的格式
- Visual Studio(或任何其他工具)能否将地址解释为调用堆栈(boost上下文)的开头
- 如何使用boost::具有嵌套结构和最小代码更改的序列化
- 使用Boost Interprocess创建托管共享内存需要很长时间
- Boost::posix_time::ptime舍入到给定的分钟数
- 为什么在单例实现中清除boost::scopedptr