1

当我将 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 上的人可以帮助我理解这个问题。我感谢任何意见或建议。

4

2 回答 2

1

似乎最困难的错误通常是最愚蠢的。

问题是我为基类分配内存,而不是派生类。我为这个结构调用了 new:

    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);

我要感谢所有帮助解决这个问题的人。

于 2011-12-18T21:16:50.073 回答
0

当您将返回类型指定RequestData为 aconst DataT*时,您传递给ProcessData函数的指针不再是常量,并且您正在调用ProcessData修改所指向对象的方法。这指出了程序设计中的一个潜在问题,在一个函数中,您返回指向常量对象的指针,但随后显然抛弃了其他函数和线程中指针的常量性质以更改底层对象。

为了正确维护const数据的-ness,返回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对象的基础属性不应更改,和/或可能不是线程安全的,从而导致发生未定义行为和段错误的机会。

于 2011-12-18T07:39:46.140 回答