Loki::Singleton、Loki::SmartPtr 和 std::vector 的奇怪内存问题
Posted
技术标签:
【中文标题】Loki::Singleton、Loki::SmartPtr 和 std::vector 的奇怪内存问题【英文标题】:Strange memory problem of Loki::Singleton, Loki::SmartPtr, and std::vector 【发布时间】:2010-11-08 19:40:15 【问题描述】:我在VC express 2008下使用Loki::Singleton、Loki::SmartPtr和std::vector时遇到了问题. 以下是我的来源。
#include <iostream>
#include <vector>
#include <loki/Singleton.h>
#include <loki/SmartPtr.h>
class Foo
public:
std::vector<Loki::SmartPtr<Foo>> children ;
void add()
Loki::SmartPtr<Foo> f = new Foo ;
children.push_back(f) ;
Foo ()
~Foo ()
;
typedef Loki::SingletonHolder<Foo> SingletonFoo ;
int main ()
std::cout << "Start" << std::endl ;
SingletonFoo::Instance().add() ;
std::cout << "End" << std::endl ;
编译链接没有问题,但是程序执行完后,弹出错误:
Windows has triggered a breakpoint in test.exe.
This may be due to a corruption of the heap, which indicates a bug in test.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while test.exe has focus.
The output window may have more diagnostic information.
似乎有些记忆被删除了两次,我不太确定。这是 VC 的错误还是我错过了使用 Loki?
提前致谢。
【问题讨论】:
【参考方案1】:当您使用 VC 时,您应该能够在调试模式下运行您的代码,通过 stp (F10,F11) 逐步查看它在哪里中断。
不管怎样,看Loki singleton code,似乎错误来自SingletonHolder::DestroySingleton() 中的断言:
SingletonHolder<T, CreationPolicy, L, M, X>::DestroySingleton()
00837
00838 assert(!destroyed_); // there, but it's a wild guess
00839 CreationPolicy<T>::Destroy(pInstance_);
00840 pInstance_ = 0;
00841 destroyed_ = true;
00842
该函数似乎由 LifetimePolicy(此处为 DefaultLifetime)调用,正如这段代码所示:
00800 template
00801 <
00802 class T,
00803 template <class> class CreationPolicy,
00804 template <class> class LifetimePolicy,
00805 template <class, class> class ThreadingModel,
00806 class MutexPolicy
00807 >
00808 void SingletonHolder<T, CreationPolicy,
00809 LifetimePolicy, ThreadingModel, MutexPolicy>::MakeInstance()
00810
00811 typename ThreadingModel<SingletonHolder,MutexPolicy>::Lock guard;
00812 (void)guard;
00813
00814 if (!pInstance_)
00815
00816 if (destroyed_)
00817
00818 destroyed_ = false;
00819 LifetimePolicy<T>::OnDeadReference();
00820
00821 pInstance_ = CreationPolicy<T>::Create();
00822 LifetimePolicy<T>::ScheduleDestruction(pInstance_, // here
00823 &DestroySingleton);
00824
00825
我不确定为什么它被调用了两次,但我猜指向单例的指针首先在 SingletonHolder 实例销毁时被销毁(指针,而不是实例),然后 LifetimePolicy 尝试调用它的 DestroySingleton() 函数...
但我可能错了,你必须检查一下。
【讨论】:
【参考方案2】:IMR,您不能在 stl 容器中使用某些智能指针,而这正是发生的问题。如果内存服务,它与 stl 容器如何复制不符合智能指针预期使用方式的值有关。
【讨论】:
我重新检查了 Loki::SmartPtr 的用法,默认策略是引用计数,与 Boost::shared_ptr 行为相同,支持值语义,可以在 STL 容器中使用。还有其他可能的解释吗?非常感谢。 如果您怀疑您的对象被删除了两次,您是否尝试过在析构函数中设置断点并检查调用堆栈?【参考方案3】:Loki 的智能指针对 STL 容器没有任何问题。如果您以这种方式重写此示例:
#include <iostream>
#include <vector>
#include <loki/Singleton.h>
#include <loki/SmartPtr.h>
class Foo
public:
std::vector<Loki::SmartPtr<Foo>> children ;
void add()
Loki::SmartPtr<Foo> f = new Foo ;
children.push_back(f) ;
Foo ()
~Foo ()
;
// typedef Loki::SingletonHolder<Foo> SingletonFoo ;
int main ()
Loki::SmartPtr<Foo> root = new Foo;
std::cout << "Start" << std::endl ;
// SingletonFoo::Instance().add() ;
root->add();
std::cout << "End" << std::endl ;
它没有任何问题。
这里发生的情况是,不应将同一类同时用作Loki::Singleton
和Loki::SmartPtr
- 它直接在Loki::Singleton
中创建和销毁,但为@987654325 维护引用计数@。
但如果你使用Loki::SmartPtr<Foo>
作为Loki::Singleton
的参数,它就可以工作!您必须对代码进行的唯一修改是 Loki::CreateUsingNew
类的特化以创建 Loki::SmartPtr<Foo>
并使用新创建的 Foo
进行初始化:
#include <iostream>
#include <vector>
#include <loki/Singleton.h>
#include <loki/SmartPtr.h>
class Foo
public:
std::vector<Loki::SmartPtr<Foo>> children ;
void add()
Loki::SmartPtr<Foo> f = new Foo ;
children.push_back(f) ;
Foo ()
~Foo ()
;
namespace Loki
template<class T>
struct CreateUsingNew<class Loki::SmartPtr<T>>
static Loki::SmartPtr<T>* Create()
return new Loki::SmartPtr<T>(new T);
static void Destroy(Loki::SmartPtr<T>* p)
delete p;
;
typedef Loki::SingletonHolder<Loki::SmartPtr<Foo>> SingletonFoo ;
int main ()
std::cout << "Start" << std::endl ;
SingletonFoo::Instance()->add() ;
std::cout << "End" << std::endl ;
【讨论】:
以上是关于Loki::Singleton、Loki::SmartPtr 和 std::vector 的奇怪内存问题的主要内容,如果未能解决你的问题,请参考以下文章