Какова причина ошибки сегментации с этим кодом C ++ с использованием списков? - PullRequest
0 голосов
/ 21 сентября 2009

У меня есть некоторый сложный код 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 ]

6 голосов
/ 22 сентября 2009

Вы пересекаете потоки. Разве вы не видели охотников за привидениями? Не пересекайте потоки.

Вы пересекаете потоки здесь:

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

За исключением того, что это называется в контексте А. Какова ценность этого? Это нигде не инициализировано. Так что это равно тому, что находится в памяти, где ждет счастливый неинициализированный список.

Исправление?

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.

4 голосов
/ 21 сентября 2009

Если я правильно помню, некоторые, если не все контейнеры STL, требуют конструктора копирования и оператора присваивания. Если вы использовали значения по умолчанию для этих двух файлов или делаете мелкую копию, когда вам следует делать глубокую копию, это может быть причиной вашей ошибки.

2 голосов
/ 21 сентября 2009

Я полагаю, список делает копию объекта cpage. Вы проверили, что конструктор копирования, если cpage не вызывает ошибку в этой ситуации?

1 голос
/ 21 сентября 2009

Вы можете дважды удалить. Деструктор cpage делает некоторую очистку? Если это так, и cpage не имеет конструктора копирования, который увеличивает refcount или делает глубокую копию, тогда очистка произойдет дважды.

1 голос
/ 21 сентября 2009

Похоже, cachedPages на самом деле не существует. Может быть, он уже был удален?

Или же f () является функцией-членом? Вы уверены, что его (this) объект все еще существует? Я был озадачен многими странными проблемами в функциях-членах, только до print *this в gdb, и понял, что я разыграл неверный указатель в следующем кадре стека.

0 голосов
/ 22 сентября 2009

Нашел ошибку: это действительно тонкий. В коде x является указателем, и он не инициализируется в базовом классе. Вызов x-> f () обращается к vtable для вызова правильной функции в производном классе B. Но, поскольку значение указателя неинициализировано, параметр "this" неверен. Попытка получить доступ к списку является недопустимой операцией, и код потерпел крах.

Чтобы исправить эту ошибку, передайте аргумент com в constrof типа T, который будет инициализирован для этого конструктором производного класса.

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

};

class B
{
public:
B() : A(this)
{
}
};
0 голосов
/ 21 сентября 2009

Необходимо указать оператор присваивания (=), чтобы процедуры сортировки могли назначать новый порядок членам списка. После этого я думаю, что ты будешь в порядке.

...