0

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

4

7 回答 7

7

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

你在这里穿越溪流:

class B : public A < B *>

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

问题不在于推回,问题在于“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就是这样完成的。

于 2009-09-22T13:02:17.573 回答
4

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

于 2009-09-21T12:29:46.987 回答
2

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

于 2009-09-21T12:27:20.503 回答
1

听起来好像cachedPages真的不存在。会不会已经被删了?

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

于 2009-09-21T12:30:41.030 回答
1

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

于 2009-09-21T13:27:05.763 回答
0

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

于 2009-09-21T13:06:38.513 回答
0

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

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

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

};

class B
{
public:
B() : A(this)
{
}
};
于 2009-09-22T07:44:40.330 回答