Запутанная ошибка сегментации

EDIT: я в основном переделал весь вопрос, чтобы предоставить исполняемый пример...

Я получаю ошибку сегментации, которую я не могу понять. Вот сжатая версия моего кода. Я сохранил исходную иерархию классов, хотя у некоторых классов нет соответствующих методов, поскольку я думаю, что это как-то связано с моей проблемой, особенно после некоторых комментариев, которые я получил.

#import <vector>
using namespace std;

template<class Data = float>
  class Vector
  {
    // All pure virtual functions.
  };

template<class Data>
  class TranslationVector : public virtual Vector<Data>
  {
    // All pure virtual functions.
  };

template<class Data>
  class SimpleVector4 : public virtual Vector<Data>
  {
    public:
      SimpleVector4(const Data d0, const Data d1, const Data d2, const Data d3)
      {
        fData = new vector<Data> ;

        fData->push_back(d0);
        fData->push_back(d1);
        fData->push_back(d2);
        fData->push_back(d3);
      }

      vector<Data>*
      getData()
      {
        return (fData);
      }

    private:
      vector<Data>* fData;
  };

template<class Data>
  class SimpleTranslationVector4 : public SimpleVector4<Data> , public TranslationVector<Data>
  {
    public:
      SimpleTranslationVector4(const Data x, const Data y, const Data z, const Data w) :
        SimpleVector4<Data> (x, y, z, w)
      {
      }
  };

template<class Data = float>
  class Matrix
  {
    // All pure virtual functions.
  };

template<class Data>
  class TransformationMatrix : public virtual Matrix<Data>
  {
    // All pure virtual functions.

    virtual void
    translate(TranslationVector<Data>* const translation) = 0;
  };

template<class Data>
  class SimpleMatrix44 : public virtual Matrix<Data>
  {
    public:
      SimpleMatrix44()
      {
        fData = new vector<Data> (CELLS_IN_MATRIX, 0);

        setIdentity();
      }

      vector<Data>*
      getData()
      {
        return (fData);
      }

      void
      setIdentity()
      {
        fData->at(0) = 1;
        fData->at(1) = 0;
        fData->at(2) = 0;
        fData->at(3) = 0;

        fData->at(4) = 0;
        fData->at(5) = 1;
        fData->at(6) = 0;
        fData->at(7) = 0;

        fData->at(8) = 0;
        fData->at(9) = 0;
        fData->at(10) = 1;
        fData->at(11) = 0;

        fData->at(12) = 0;
        fData->at(13) = 0;
        fData->at(14) = 0;
        fData->at(15) = 1;
      }

    private:
      static const int CELLS_IN_MATRIX = 16;

      vector<Data>* fData;
  };

template<class Data>
  class SimpleTransformationMatrix44 : public SimpleMatrix44<Data> , public TransformationMatrix<Data>
  {
    public:
      SimpleTransformationMatrix44() :
        SimpleMatrix44<Data> ()
      {
      }

      void
      translate(TranslationVector<Data>* translation)
      {
        vector<Data> *data = SimpleMatrix44<Data>::getData();
        vector<Data> *transData = ((SimpleVector4<Data>*) translation)->getData();

        // The error occurs on this line:
        data->at(12) += data->at(0) * transData->at(0) + data->at(4) * transData->at(1) + data->at(8) * transData->at(2);
        data->at(13) += data->at(1) * transData->at(0) + data->at(5) * transData->at(1) + data->at(9) * transData->at(2);
        data->at(14) += data->at(2) * transData->at(0) + data->at(6) * transData->at(1) + data->at(10) * transData->at(2);
        data->at(15) += data->at(3) * transData->at(0) + data->at(7) * transData->at(1) + data->at(11) * transData->at(2);
      }
  };

int
main(int argc, char** argv)
{
  SimpleTransformationMatrix44<float> matrix1;
  matrix1.translate(new SimpleTranslationVector4<float> (0.0f, 10.0f, 0.0f, 1.0f));

  return 0;
}

Я прокомментировал код, где возникает ошибка. Из отладки я вижу, что это действительно происходит в функции size() vector и что transData не инициализирован. Я не могу понять, почему transData не был инициализирован! Любые идеи?

Спасибо,

Газ.


person Gyan aka Gary Buyn    schedule 08.07.2011    source источник
comment
Не могли бы вы рассказать подробнее о том, как transData получается? Например. как определяется SimpleVector4<Data>::getData(). Как TranslationVector<Data> относится к SimpleVector4<Data>. Почему вы отбрасываете const. Как определяется SimpleTranslationVector4<float>. И т. д.   -  person Sander De Dycker    schedule 08.07.2011
comment
(SimpleVector4<Data>*) translation почему это типизация?   -  person iammilind    schedule 08.07.2011
comment
Это звучит как интересный вопрос, и я хотел бы попробовать его, но вы не предоставили что-то, что я мог бы легко скомпилировать и запустить, поэтому мое внимание переключится на что-то еще. Пока. sscce.org   -  person David Grayson    schedule 08.07.2011
comment
Выделение vectors в куче избыточно.   -  person n. 1.8e9-where's-my-share m.    schedule 08.07.2011
comment
@н.м. Действительно? Это почему? Их содержимое по своей сути находится в куче?   -  person Gyan aka Gary Buyn    schedule 08.07.2011
comment
@David Спасибо за совет! Я посмотрю что я могу сделать.   -  person Gyan aka Gary Buyn    schedule 08.07.2011
comment
vector под капотом — это просто указатель и длина. Указанный массив размещается в куче. Одного выделения достаточно. Если ваш вектор имеет фиксированную длину, вам даже не нужна куча, boost::array будет работать так же хорошо, как и массив C-стиля (но последний не так хорош).   -  person n. 1.8e9-where's-my-share m.    schedule 08.07.2011
comment
@н.м. Имеет смысл. Моя главная мотивация поместить их в кучу заключается в том, что они являются частью механизма рендеринга, и я ожидаю, что в памяти могут быть одновременно тысячи матриц. Я отошел от массива C-стиля, потому что они не кажутся очень безопасными. Мне нужно будет проверить буст, так как я уже использую некоторые вещи из их библиотек. Спасибо!   -  person Gyan aka Gary Buyn    schedule 08.07.2011
comment
Спасибо за упрощение вашего примера.   -  person David Grayson    schedule 08.07.2011


Ответы (2)


Вы делаете приведение в стиле C между несвязанными типами. Это небезопасно. Тот факт, что вам вообще нужно это сделать, вероятно, указывает на проблему в вашем дизайне, но попробуйте заменить это:

vector<Data>* transData = ((SimpleVector4<Data>*) translation)->SimpleVector4<Data>::getData();

с этим:

vector<Data>* transData = dynamic_cast<SimpleVector4<Data>*>(translation)->getData();

person bshields    schedule 08.07.2011
comment
Это работает! Однако я не хочу плохо спроектированного кода... Теперь, когда у меня есть правильный пример в моем вопросе, не могли бы вы взглянуть и посмотреть, считаете ли вы, что плохой дизайн привел меня к этой ситуации? Возможно, плохая иерархия? У меня есть опыт работы с Java, и я перехожу на C++, поэтому мой стиль кода может слишком сильно имитировать Java. Спасибо. - person Gyan aka Gary Buyn; 08.07.2011

Состав неунаследованных классов кажется вашей ошибкой.

Давайте посмотрим ваш код. При вызове функции перевода происходит преобразование SimpleTranslationVector4<float>* в TranslationVector<float>*. Затем преобразованное значение снова преобразуется в SimpleVector4<float>*. Но SimpleVector4<float> не наследует TranslationVector<float>.

Этот код также приводит к ошибке.

template<class Data>
class SimpleVector4 {
public:
    int a;
};

template<class Data>
class TranslationVector {
};

template<class Data>
class SimpleTranslationVector4 : public SimpleVector4<Data>,
public TranslationVector<Data> {
};

int main() {
    SimpleTranslationVector4<float> A;
    SimpleVector4<float>* b = (SimpleVector4<float>*)&A;
    TranslationVector<float>* c = (TranslationVector<float>*)&A;
    SimpleVector4<float>* d = (SimpleVector4<float>*)c;
    b->a = 1; // ok
    d->a = 1; // error
}
person eugene_che    schedule 08.07.2011
comment
Это отличный пример. Между вашим ответом и ответом @bshields я думаю, что лучше понимаю, где я ошибся. Как я прокомментировал его ответ, я родом из Java, и я думаю, что все приведения в Java должны быть динамическими. - person Gyan aka Gary Buyn; 08.07.2011
comment
@ Гэри Байн. Постараюсь объяснить понятнее. После приведения translation к SimpleVector4* это указывает на неправильную ячейку памяти. Таким образом, translation->getData() возвращает неправильный указатель, что приводит к неопределенному поведению. Компилятор С++ просто не знает, как преобразовать TranslationVector* в SimpleVector4*. Вы можете помочь двойным приведением (SimpleVector4*)(SimpleTranslationVector4*)translation, и это сработает, но это не очень хороший подход к дизайну. Прочтите это для получения более подробной информации. P.S. извините, если вы получили это сообщение дважды. - person eugene_che; 08.07.2011