Странная проблема с памятью Loki::Singleton, Loki::SmartPtr и std::vector

Я столкнулся с проблемой при использовании Loki::Singleton, Loki::SmartPtr и std::vector в VC Express 2008. Ниже приведено мой источник.

#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.

Кажется часть памяти удаляется дважды, я совсем не уверен. Это баг ВК или я скучаю по б/у Локи?

Заранее спасибо.


person yoco    schedule 07.07.2009    source источник


Ответы (2)


Поскольку вы используете VC, вы должны иметь возможность запускать свой код в режиме отладки, шаг за шагом (F10, F11), чтобы увидеть, где он ломается.

В любом случае, глядя на одиночный код Loki, кажется, что ошибка возникает из-за утверждение в 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()...

Но я могу ошибаться, вам придется это проверить.

person Klaim    schedule 07.07.2009

IMR, вы не можете использовать определенные интеллектуальные указатели в stl-контейнерах, и это именно та проблема, которая возникает. Если память не изменяет, это связано с тем, как контейнеры stl копируют значения, не соответствующие ожидаемому использованию интеллектуальных указателей.

person Not Sure    schedule 07.07.2009
comment
Я перепроверил использование Loki::SmartPtr, политикой по умолчанию является счетчик ссылок, который имеет то же поведение, что и Boost::shared_ptr, поддерживает семантику значений и может использоваться в контейнере STL. Есть ли другое возможное объяснение? Большое спасибо. - person yoco; 08.07.2009
comment
Если вы подозреваете, что ваши объекты удаляются дважды, пробовали ли вы вставлять точки останова в свой деструктор и проверять стек вызовов? - person Not Sure; 08.07.2009