Закрытый член вектора динамического распределения памяти - PullRequest
4 голосов
/ 16 марта 2011

Я новичок в C ++ (я изучал программирование на Фортране), и я хотел бы динамически распределять память для многомерной таблицы. Эта таблица является закрытой переменной-членом:

class theclass{
public:
  void setdim(void);
private:
  std::vector < std::vector <int> > thetable;
}

Я бы хотел установить размер таблицы с помощью функции setdim ().

void theclass::setdim(void){
  this->thetable.assign(1000,std::vector <int> (2000));
}

У меня нет проблем с компиляцией этой программы, но при ее выполнении возникает ошибка сегментации.

Странно для меня то, что этот фрагмент кода (см. Ниже) делает именно то, что я хочу, за исключением того, что он не использует переменную private члена моего класса:

std::vector < std::vector < int > > thetable;
thetable.assign(1000,std::vector <int> (2000));

Кстати, у меня нет проблем, если таблица является одномерным вектором. В классе:

std::vector < int > thetable;

и если в setdim:

this->thetable.assign(1000,2);

Итак, мой вопрос: почему существует такая разница с «назначить» между таблицей и этой-> таблицей для двумерного вектора? И как мне поступить так, как я хочу?

Спасибо за помощь,

С уважением,

- Жоффруа

Ответы [ 4 ]

1 голос
/ 16 марта 2011

Так как он работает с локальной, а не с вашей переменной класса, мои способности по отладке психики говорят мне, что вы звоните setdim по нулевому или недействительному указателю / экземпляру theclass.

0 голосов
/ 31 марта 2011

Хотя многим нравится ваш подход, если вы хотите, чтобы он был быстрым (как, например, с матрицей, вам нужен отдельный блок памяти и индексируйте его самостоятельно.

ЕстьЭто объясняется несколькими причинами. Во-первых, вам нужно выделить один блок памяти для вектора верхнего уровня и один вектор для каждой строки (или столбца, поскольку вы из земли FORTRAN ....)

Таким образом, вместо одной операции у вас есть n + 1.

Это применяется каждый раз, когда вы обрабатываете этот объект, копируете, уничтожаете, что у вас есть. Вы также сохраняете издержки вектора (размер, емкость) для каждой строки. Конечно, если каждая строка имеет разный размер, это особенность.

Итак, рассмотрим следующее, жестко закодированное для удвоения для ясности: посмотрите, насколько прост конструктор, и насколько простоперация, аналогичная + =, так как она может просто последовательно проходить весь блок, игнорируя индексацию.

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

Произвольная индексация обеспечивается в операторе ()

class Matrix {
private:
  int m_rows, m_cols;
  double* m_data;
public:
  Matrix(int rows, int cols) : m_rows(rows), m_cols(cols), m_data(new double[rows*cols]
  {}

  ~Matrix() { delete [] m_data; }
  Matrix(const Matrix& orig) m_rows(orig.m_rows), m_cols(orig.m_cols),
              m_data(new double[m_rows * m_cols]
  {}
  // operator = too....


  Matrix& operator +=(const Matrix& right) {
    assert(m_rows == right.m_rows && m_cols == right.m_cols);
    for (int i = 0; i < m_rows*m_cols; i++)
      m_data[i] += right.m_data[i];
  }

  double& operator()(int r, int c) { return m_data[r * m_cols + c]; }
  double operator()(int r, int c) const { return m_data[r * m_cols + c]; }
};
0 голосов
/ 16 марта 2011

Одну вещь за раз:

1) Код более полезен в объяснении, так как большинство людей пропускают действительно важный бит.Так что конвертируйте ваш код в простейший компилируемый пример, который вы можете затем поместить здесь.

Поскольку у вас нет указателей, этот обычно означает, что вы вышли за пределы массива.Примечание: к массивам C обращаются из 0 -> (n-1), поэтому массив из 1000 элементов имеет элементы 0 -> 999. Если вы обращаетесь к концу массива, приложение не будет жаловаться, но вы испортите память.*

Для проверки этого оператора преобразования [] в идентификаторы .at ().

thetable[0][5] = BLA

thetable.at(0).at(5) = BLA  // This tests the bounds and will 
                            // throw an exception if you make a mistake.

3) связываются с переменной с ближайшей областью действия.Поэтому рекомендуется назначать уникальные имена вашим идентификаторам, чтобы они не конфликтовали.«thetable» относится к локальной переменной, тогда как this-> thetable относится к члену.Проще дать им уникальные имена.

std::vector < std::vector < int > > thetable;
thetable.assign(1000,std::vector <int> (2000));

// This is not a good idea if you have a member called thetable.
// Some people (not me) like to prefix member variables with m_ to distinguish
// them from automatic local variables.

class theclass
{
     Type   m_thetable;

     void theMethod()
     {
         Type thetable;
         m_thetable = thetable;
     }
0 голосов
/ 16 марта 2011

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

#include <vector>

в одном из исходных файлов (основной, но не с определением класса). Это странно для меня, потому что без него я не понимаю, как он может компилироваться ... Так что это должен быть другой вопрос, но я все еще не понимаю, куда поместить эти #include ... Жизнь с Fortran была проще ; -)

Еще раз спасибо,

- Жоффруа

...