使用列表使用此C ++代码进行分段错误的原因是什么?

时间:2009-09-21 12:25:04

标签: c++ list stl segmentation-fault

我有一些复杂的C ++代码,但问题缩小到在结构列表上执行push_back

list<cache_page> cachedPages;

void f()
{
    cache_page cpage(a,b);
    cachedPages.push_back(cpage);
}

我已评论struct cache_page的所有数据成员,但错误仍然存​​在。如果我评论push_back行,则没有错误。

可能是什么原因?

我尝试使用GDB,错误发生在_List_Node_base::hook()函数中。

template < class T >
class A
{
    T x;
    public:
        void func()
        {
          x->f();
        }

};

class B : public A < B* >
{
    list<cache_page> cachedPages;
    public:
        void f()
        {
            cache_page cpage;
            cachedPages.push_back(cpage);
        }
};

我没有做任何复制构造函数。我在cache_page中没有数据成员。

7 个答案:

答案 0 :(得分:6)

你正在穿越溪流。你没见过捉鬼敢死队吗?不要越过溪流。

你在这里穿过溪流:

class B : public A < B *>

我不明白这一点。你想做什么? CRTP?这不是它的方式。

问题不在于推迟,问题是“这个”无效。

当你有

  void f()
  {
    cache_page cpage;
  }

它被编译为NOP。这不是一切都很好。

  void f()
  {
    cache_page cpage;
    // oops this access
    this->cachedPages.push_back(cpage);
  }

除了在A.的背景下调用它有什么价值?它没有在任何地方初始化。所以这等于内存中的任何内容,其中一个快乐的未初始化列表正在等待。

修复?

template < class T >
class A
{
  T * _x;
public:
 explicit A(T * x) : _x(x) {}

 void func()
 {
   _x->f();
 }

};


class B : public A < B >
{
  list<cache_page> cachedPages;
public:
  B(void) : A<B>(this) {}

  void f()
  {
    cache_page cpage;
    cachedPages.push_back(cpage);
  }
};

这应该更好。但是呢......

template < class T >
class A
{
public:
 void func()
 {
   static_cast<T>(this)->f();
 }

};


class B : public A<B>
{
  list<cache_page> cachedPages;
public:
  void f()
  {
    cache_page cpage;
    cachedPages.push_back(cpage);
  }

};

这就是CRTP的完成方式。

答案 1 :(得分:4)

如果我没记错的话,有些(如果不是全部)STL容器都需要复制构造函数和赋值运算符。如果您依赖于这两者的默认值,或者在进行深层复制时正在执行浅层复制,则可能是您的段错误的原因。

答案 2 :(得分:2)

我猜list会复制页面对象,你是否检查过复制构造函数,如果页面没有在那种情况下发生段错误?

答案 3 :(得分:1)

听起来cachedPages并不存在。它可能已被删除了吗?

或者,f()是成员函数吗?你确定它的(this)对象仍然存在吗?我一直对成员函数中的许多奇怪的问题感到困惑,只对gdb中的print *this感到困惑,并意识到我在下一个堆栈帧中已经取消引用了一个错误的指针。

答案 4 :(得分:1)

您可能会被双重删除。 cpage的析构函数是否进行了一些清理?如果是这种情况,并且cpage没有复制构造函数来增加引用计数或进行深度复制,那么清理将发生两次。

答案 5 :(得分:0)

您需要指定赋值(=)运算符,以便排序例程可以为列表成员分配新订单。在那之后我觉得你没事。

答案 6 :(得分:0)

发现错误:它是一个非常微妙的错误。 在代码中,x是一个指针,它没有在基类中初始化。调用x-&gt; f()访问vtable以在派生类B中调用正确的函数。 但是,由于指针值未初始化,因此“this”参数错误。然后尝试访问列表是无效操作,代码崩溃。

要纠正此错误,请在constrof类型T中传递com的参数,该参数将由派生类的构造函数初始化为此。

class A
{
public:
A(T p): x(p)
{
}

};

class B
{
public:
B() : A(this)
{
}
};