【问题标题】:What is the reason for a segmentation fault with this C++ code using lists?使用列表的此 C++ 代码出现分段错误的原因是什么?
【发布时间】:2009-09-21 12:25:04
【问题描述】:

我有一些复杂的 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 中没有数据成员。

【问题讨论】:

  • 您的列表的确切类型是什么? (list 或 list 或任何智能指针类?)
  • 列表 cachedPages;
  • 列表在哪里声明,在哪里实例化?可能有很多原因。
  • 出于测试目的,您可以在 B 类中再添加一个成员变量,并尝试访问它而不是 f() 中的列表。如果它仍然崩溃,那么 A 类中的 x->f() 正在尝试对无效的 x 进行操作。
  • 发布cache_page 代码。如果您在list&lt;cache_page&gt; 中收到错误,可以很安全地假设问题出在cache_page 而不是list

标签: c++ list stl segmentation-fault


【解决方案1】:

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

你正在这里穿越溪流:

class B : public A < B *>

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

问题不在push back,问题是“this”无效。

当你有

  void f()
  {
    cache_page cpage;
  }

它被编译为 NOP。这没有加入一切都很好。

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

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

解决办法?

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就是这样完成的。

【讨论】:

  • static_cast 不应该是(static_cast&lt;T*&gt;(this))-&gt;f(); 此外,使用 static_cast 将基类指针强制转换为派生类指针是否有效。不应该使用动态演员表。当然,类 A 不知道类型 T 是派生类。我很困惑。
  • 我检查了程序,应该对 T* 进行 static_cast。而且我没有意识到我们不能进行动态转换,因为没有多态性。我需要复习基础知识。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    我猜 list 会复制 cpage 对象,如果 cpage 在这种情况下没有段错误,你检查过复制构造函数吗?

    【讨论】:

    • 我有一个什么都不做的复制构造函数。当我执行 push_back 时调用它。但我在 cache_page 结构中没有任何数据成员。
    【解决方案4】:

    听起来cachedPages 并不存在。会不会已经被删除了?

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

    【讨论】:

    • 是的 f() 是一个成员函数。参见上面的代码 sn-p。我有一个单线程程序,我可以在 f() 中做其他事情而不会出现分段错误。这表明 *this 不为空。
    【解决方案5】:

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

    【讨论】:

      【解决方案6】:

      您需要指定赋值 (=) 运算符,以便排序例程可以将新顺序分配给列表的成员。之后我想你会没事的。

      【讨论】:

      • 好的,我尝试按照您发布的代码进行操作...编译正常,调用 f() 时没有错误。请贴出可以可靠复现错误的代码sn-p。
      【解决方案7】:

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

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

      class A
      {
      public:
      A(T p): x(p)
      {
      }
      
      };
      
      class B
      {
      public:
      B() : A(this)
      {
      }
      };
      

      【讨论】:

        猜你喜欢
        • 2021-04-09
        • 2019-10-23
        • 1970-01-01
        • 2019-05-01
        • 2017-02-20
        • 1970-01-01
        • 1970-01-01
        • 2011-01-19
        • 1970-01-01
        相关资源
        最近更新 更多