У меня возникли некоторые трудности с диагностикой ошибки сегментации в результате или, по крайней мере, я думаю, что это связано с статическим классом template'd (см. Исходный пост здесь Help understanding segfault with std::map/boost::unordered_map).Странное поведение со статическим классом template'd
После публикации, что я нашел в моей программе какое-то другое странное поведение. Я никогда не сталкивался с чем-либо подобным, и я думаю, что я должен не знать некоторых тонких деталей о том, как работают шаблоны, в результате чего я что-то делаю неправильно.
Я пытался бездумно реорганизовать вещи, чтобы попытаться устранить проблему, но она по-прежнему сохраняется.
Наиболее озадачивает симптом заключается в следующем: в одном исходном файле (Menu.cpp) У меня есть следующие три вызовов:
Font::init();
// later
g_font = Font::get("Mono.ttf");
// later
Font::release();
В другом исходном файле (Game.cpp) У меня почти такой же три линий. Почти весь код в Menu.cpp выполняется до того, как все будет выполнено в Game.cpp.
Теперь все в порядке с этим. Однако, если я просто закомментируйте
g_font = Font::get("Arial.ttf");
в Game.cpp программа встречает ошибку сегментации на g_font = ...
в Menu.cpp (примечание: все в Menu.cpp и Game.cpp имеют свое собственное пространство имен). Но NO код даже был выполнен в Game.cpp на этом этапе!
Теперь, если я свяжусь с Menu.o до Game.o, проблема исчезнет (но другая проблема существует в другом месте). Что я здесь не понимаю?
Я использовал отладчик, чтобы перейти через программу, чтобы узнать, что происходит. Когда строка g_font
прокомментирована в Game.cpp, контейнер повышения (unordered_map) в базовом классе Font Resource каким-то образом не инициализируется правильно. В частности, buckets_
и size_
неинициализированы и приводят к неустойчивому поведению. Я пробовал использовать std :: map и аналогичные проблемы.
Вот полный список для Font.hpp
#ifndef __Font_hpp__
#define __Font_hpp__
#include <string>
#include "Vector.hpp"
#include "Resource.hpp"
class FTPixmapFont;
/*!
* Adapter class for FTGL's FTPixmapFont
*/
class Font : public Resource<Font>
{
public:
Font(const std::string& fileName);
~Font();
void render(const std::string& str, const Vector& pos, int ptSize=14) const;
private:
FTPixmapFont *m_font;
};
#endif // __Font_hpp__
Вот полный список для Resource.hpp (это
потенциально
утечки памяти прямо сейчас на release()
, я был первоначально используя boost::shared_ptr
в контейнере, но переключились на сырые указатели, думая, что все это исправит, да).
#ifndef __Resource_hpp__
#define __Resource_hpp__
#include <string>
#include <map>
#include <boost/unordered_map.hpp>
#include <boost/utility.hpp>
#include "debug.hpp"
#include "assert.hpp"
#define MAP_TYPE boost::unordered_map
/*!
* Resource base class.
*/
template <class T>
class Resource : public boost::noncopyable
{
public:
static void init(const std::string& dir="data")
{
ASSERT(!c_init);
if (*dir.rbegin() == '/') {
c_dataDirectory = dir;
} else {
c_dataDirectory = dir + '/';
}
c_init = true;
}
static void release()
{
ASSERT(c_init);
c_dataDirectory.clear();
c_resources.clear();
c_init = false;
}
static const T *get(const std::string& fileName)
{
T *resource = NULL;
typename MAP_TYPE<std::string, T*>::const_iterator itr = c_resources.find(fileName);
if (itr == c_resources.end()) {
resource = new T(c_dataDirectory + fileName);
c_resources.insert(std::pair<std::string, T*>(fileName, resource));
} else {
resource = itr->second;
}
return resource;
}
private:
static bool c_init;
static std::string c_dataDirectory;
static typename MAP_TYPE<std::string, T*> c_resources;
};
template <class T> bool Resource<T>::c_init = false;
template <class T> std::string Resource<T>::c_dataDirectory;
template <class T> MAP_TYPE<std::string, T*> Resource<T>::c_resources;
#endif // __Resource_hpp__
Вот некоторые вывода (трассировка стека) из GDB с MAP_TYPE = boost::unordered_map
:
Reading symbols from /home/tim/Projects/gameproj/app/game...done.
(gdb) r
Starting program: /home/tim/Projects/gameproj/app/game
[Thread debugging using libthread_db enabled]
Program received signal SIGSEGV, Segmentation fault.
0x0000000000499aca in boost::unordered_detail::hash_table<boost::unordered_detail::map<std::string, boost::hash<std::string>, std::equal_to<std::string>, std::allocator<std::pair<std::string const, Font*> > > >::find_iterator (this=0x79bd80,
bucket=0x20, k=...) at /usr/local/include/boost/unordered/detail/table.hpp:55
55 node_ptr it = bucket->next_;
(gdb) bt
#0 0x0000000000499aca in boost::unordered_detail::hash_table<boost::unordered_detail::map<std::string, boost::hash<std::string>, std::equal_to<std::string>, std::allocator<std::pair<std::string const, Font*> > > >::find_iterator (this=0x79bd80,
bucket=0x20, k=...) at /usr/local/include/boost/unordered/detail/table.hpp:55
#1 0x0000000000499872 in boost::unordered_detail::hash_table<boost::unordered_detail::map<std::string, boost::hash<std::string>, std::equal_to<std::string>, std::allocator<std::pair<std::string const, Font*> > > >::find (this=0x79bd80, k=...)
at /usr/local/include/boost/unordered/detail/table.hpp:583
#2 0x00000000004994fb in boost::unordered_map<std::string, Font*, boost::hash<std::string>, std::equal_to<std::string>, std::allocator<std::pair<std::string const, Font*> > >::find (this=0x79bd80, k=...)
at /usr/local/include/boost/unordered/unordered_map.hpp:423
#3 0x00000000004992ab in Resource<Font>::get (fileName=...) at /home/tim/Projects/gameproj/app/Resource.hpp:45
#4 0x0000000000498e23 in Menu::init (xResolution=1024, yResolution=768) at /home/tim/Projects/gameproj/app/Menu.cpp:57
#5 0x0000000000498ce1 in Menu::run (xResolution=1024, yResolution=768) at /home/tim/Projects/gameproj/app/Menu.cpp:23
#6 0x0000000000481275 in Main::run (xResolution=1024, yResolution=768) at /home/tim/Projects/gameproj/app/Main.cpp:25
#7 0x0000000000481135 in main (argc=1, argv=0x7fffffffe398) at /home/tim/Projects/gameproj/app/main.cpp:10
(gdb)
Вот некоторые вывода (трассировка стека) из GDB с MAP_TYPE = std::map
:
Reading symbols from /home/tim/Projects/gameproj/app/game...done.
(gdb) r
Starting program: /home/tim/Projects/gameproj/app/game
[Thread debugging using libthread_db enabled]
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff701ae4d in std::string::compare(std::string const&) const() from /usr/lib/libstdc++.so.6
(gdb) bt
#0 0x00007ffff701ae4d in std::string::compare(std::string const&) const() from /usr/lib/libstdc++.so.6
#1 0x0000000000480c2d in std::operator< <char, std::char_traits<char>, std::allocator<char> > (__lhs=..., __rhs=...)
at /usr/include/c++/4.4/bits/basic_string.h:2320
#2 0x0000000000480a15 in std::less<std::string>::operator() (this=0x772d60, __x=..., __y=...)
at /usr/include/c++/4.4/bits/stl_function.h:230
#3 0x0000000000480691 in std::_Rb_tree<std::string, std::pair<std::string const, Font*>, std::_Select1st<std::pair<std::string const, Font*> >, std::less<std::string>, std::allocator<std::pair<std::string const, Font*> > >::find (this=0x772d60,
__k=...) at /usr/include/c++/4.4/bits/stl_tree.h:1424
#4 0x0000000000480465 in std::map<std::string, Font*, std::less<std::string>, std::allocator<std::pair<std::string const, Font*> > >::find (this=0x772d60, __x=...) at /usr/include/c++/4.4/bits/stl_map.h:659
#5 0x000000000048027d in Resource<Font>::get (fileName=...) at /home/tim/Projects/gameproj/app/Resource.hpp:45
#6 0x000000000047ff97 in Menu::init (xResolution=1024, yResolution=768) at /home/tim/Projects/gameproj/app/Menu.cpp:57
#7 0x000000000047fe55 in Menu::run (xResolution=1024, yResolution=768) at /home/tim/Projects/gameproj/app/Menu.cpp:23
#8 0x000000000046a725 in Main::run (xResolution=1024, yResolution=768) at /home/tim/Projects/gameproj/app/Main.cpp:25
#9 0x000000000046a5e5 in main (argc=1, argv=0x7fffffffe398) at /home/tim/Projects/gameproj/app/main.cpp:10
Я также используется Valgrind, ошибок нет, кроме случаев, когда возникает ошибка сегментации.
Я использую CMake для создания Makefile, gcc 4.4.3 и boost 1.43. Я строю на 64-битной машине Ubuntu.
Любая помощь по этому поводу будет очень благодарна, я чувствую, что с ней ничего не получается. Тем временем я собираюсь попытаться построить другую платформу/машину, чтобы убедиться, что я получаю такое же поведение.
Является ли ваша программа многопоточной? У вас нет блокировки. – Stephen
В настоящее время существует только одна тема. – Tim
http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12 – Anycorn