Ошибка сегмента при использовании списка инициализаторов c ++ 0x - PullRequest
1 голос
/ 18 декабря 2011

Я получаю ошибку сегмента, когда использую список инициализатора c ++ 0x с вектором. Я не могу понять, почему это происходит. Мой отладчик говорит, что сбой происходит при этой функции в стандартной библиотеке:

  template<typename _T1, typename _T2>
    inline void
#ifdef __GXX_EXPERIMENTAL_CXX0X__
// Allow perfect forwarding
_Construct(_T1* __p, _T2&& __value)
#else
_Construct(_T1* __p, const _T2& __value)
#endif
{
  // _GLIBCXX_RESOLVE_LIB_DEFECTS
  // 402. wrong new expression in [some_]allocator::construct
  ::new(static_cast<void*>(__p)) _T1(_GLIBCXX_FORWARD(_T2, __value));
}

Я пытался определить назначение этой функции, но не могу найти объяснения / документацию в Интернете.

Код, который использует список инициализатора в моем коде, выглядит следующим образом:

bool Cube::ProcessData(MeshData* data)
{
    data->Clear();

    data->v =
    {
        Vec3(.5,-.5,-.5), Vec3(.5,-.5,.5), Vec3(-.5,-.5,.5), Vec3(-.5,-.5,-.5),
        Vec3(.5, .5,-.5), Vec3(.5, .5,.5), Vec3(-.5, .5,.5), Vec3(-.5, .5,-.5)
    };
...
}

Структура данных, которая передается этой функции, создается здесь:

    template <class ProcessorT, class DataT, typename... Args>
    const DataT* DataManager::RequestData(Args... args)
    {
        MutexLock lock(*mutex);

        Request req;

        data_cache.PushBack();
        req.data      = &data_cache.GetBack();
        req.processor = new ProcessorT(args...);
        request_list.push_back(req);

        return static_cast<DataT*>(req.data);
    }

Структура data_cache - это мой собственный класс списка, который я использую, чтобы избежать копирования. Функция ProcessData вызывается из потока, отличного от того, в котором создана структура данных.

И это вывод отладчика для стека вызовов:

#0 004FAAD6 _Construct<UtilityLib::TVec3<float>, UtilityLib::TVec3<float> const&>(this=0x104aba0, __first=0x593fb98, __last=0x593fbf8) (c:/mingw/bin/../lib/gcc/mingw32/4.5.2/include/c++/bits/stl_construct.h:80)
#1 00000000 uninitialized_copy<UtilityLib::TVec3<float> const*, UtilityLib::TVec3<float>*>(this=0x104aba0, __first=0x593fb98, __last=0x593fbf8) (c:/mingw/bin/../lib/gcc/mingw32/4.5.2/include/c++/bits/stl_uninitialized.h:74)
#2 00000000 uninitialized_copy<UtilityLib::TVec3<float> const*, UtilityLib::TVec3<float>*>(this=0x104aba0, __first=0x593fb98, __last=0x593fbf8) (c:/mingw/bin/../lib/gcc/mingw32/4.5.2/include/c++/bits/stl_uninitialized.h:116)
#3 00000000 __uninitialized_copy_a<UtilityLib::TVec3<float> const*, UtilityLib::TVec3<float>*, UtilityLib::TVec3<float> >(this=0x104aba0, __first=0x593fb98, __last=0x593fbf8) (c:/mingw/bin/../lib/gcc/mingw32/4.5.2/include/c++/bits/stl_uninitialized.h:318)
#4 00000000 std::vector<UtilityLib::TVec3<float>, std::allocator<UtilityLib::TVec3<float> > >::_M_assign_aux<UtilityLib::TVec3<float> const*>(this=0x104aba0, __first=0x593fb98, __last=0x593fbf8) (c:/mingw/bin/../lib/gcc/mingw32/4.5.2/include/c++/bits/vector.tcc:260)
#5 004127B3 _M_assign_dispatch<UtilityLib::TVec3<float> const*>(this=0x6e8af18, data=0x104ab98) (c:/mingw/bin/../lib/gcc/mingw32/4.5.2/include/c++/bits/stl_vector.h:1065)
#6 00000000 assign<UtilityLib::TVec3<float> const*>(this=0x6e8af18, data=0x104ab98) (c:/mingw/bin/../lib/gcc/mingw32/4.5.2/include/c++/bits/stl_vector.h:396)
#7 00000000 operator=(this=0x6e8af18, data=0x104ab98) (c:/mingw/bin/../lib/gcc/mingw32/4.5.2/include/c++/bits/stl_vector.h:359)
#8 00000000 GameEngine::Render3D::Cube::ProcessData(this=0x6e8af18, data=0x104ab98) (C:\CodeBlocksProjects\GameEngine\src\Primitives.cpp:56)

Я подозреваю, что мой класс списка может быть виновником, но даже если это так, я не знаю почему. Надеюсь, кто-то в StackOverflow поможет мне разобраться в этой проблеме. Я ценю любые советы или предложения.

Ответы [ 2 ]

1 голос
/ 19 декабря 2011

Кажется, что самые сложные ошибки, как правило, самые глупые.

Проблема заключалась в том, что я выделял память для базового класса, а не для производного.Я назвал новый для этой структуры:

    class Data
    {
    public:
        enum State { LOADED, UNLOADED, FAILED };
        Data();
        virtual ~Data();
        State state;
    };

Когда я должен был выделить память для этой структуры:

    struct MeshData : public Data
    {
        vector<Vec3>    v, n;
        vector<Vec2>    u;
        vector<Polygon> p;

        MeshData();
        ~MeshData();
        void Clear();
        string Str()      const;
        string StrStats() const;

        bool IsValid() const;
        bool IsValid(bool& has_n, bool& has_u, bool& all_tri) const;
};

, поэтому всякий раз, когда я пытаюсь получить доступ к экземпляру MeshData, я обращался кпамять за пределами структуры.

Так что я был прав, предполагая, что мой класс List был виновником (своего рода).Я добавил средство для указания типа выделения:

template <typename TT, typename... Args> void PushBackT(Args... args);

Я хотел бы поблагодарить всех, кто помог с этой проблемой.

0 голосов
/ 18 декабря 2011

Пока вы обозначаете возвращаемый тип RequestData как const DataT*, указатель, который вы передаете своей функции ProcessData, больше не является константой, и вы вызываете методы в ProcessData, которые изменяютобъект, на который указываютЭто указывает на основную проблему в дизайне вашей программы, когда в одной функции вы возвращаете указатели на постоянные объекты, но затем явно отбрасываете постоянную природу указателя в других функциях и потоках, чтобы изменить базовый объект.

Чтобы должным образом поддерживать const -ность данных, обычно рекомендуется возвращать const T& для эталонного объекта, который не должен изменяться вызывающей стороной.Если вы не пытаетесь поддерживать какой-либо тип совместимости с внешним API, вы должны продолжать использовать указатели возвращаемых типов для объектов, которые впоследствии могут быть изменены.Из-за обратной совместимости C ++ с приведением в стиле C слишком просто отказаться от защиты const при использовании типов указателей.Ссылки с другой стороны могут предоставить вам гораздо больший контроль над поддержанием const -объекта объекта от вызова функции до вызова функции.Требуется явная операция const_cast, чтобы удалить const -нессность объекта с постоянной ссылкой (или некоторых относительно тупых приведений в стиле C), где-как приведение в стиле C может лишить указатель постоянной природыобъект, просто делая что-то вроде:

const int* test1() { static int a; return &a; }
void test2(int* a){}

const int* b = test();
test2((int*)b);

Хотя вышеприведенное не указывает конкретную причину вашей ошибки сегментации, я верю в тот факт, что вы модифицируете память, которая первоначально была обозначена как константаобозначает базовый атрибут вашего data объекта, который не должен изменяться и / или может не быть потокобезопасным, что приводит к возможности возникновения неопределенного поведения и ошибок сегмента.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...