SIGSEGV при резервировании вектора, хранящегося в классе - PullRequest
0 голосов
/ 04 марта 2020

( см. Редактирование ). Это минимальный пример проблемы, с которой я столкнулся в большом фрагменте кода (см. Код ниже). У меня есть несколько векторов, которые используются для хранения входных данных. Эти векторы не имеют установленного размера до тех пор, пока не будут считаны некоторые данные. После того, как данные считаны, данные сохраняются в векторах, поэтому мне нужно установить размер векторов, заполнить векторы, а затем продолжить использовать векторы для других целей (вот почему я подумал о том, чтобы бросить их в классе). У меня был некоторый тестовый код, который делал все это очень хорошо (похоже на foo() ниже), а затем перенес все это в мой рабочий код (аналогично bar() ниже). Тем не менее, bar() segfaults, и я не уверен, почему. Есть ли правильный способ сохранить вектор и зарезервировать его / заполнить позже для использования в таком классе, как этот?

#include <iostream>
#include <vector>

int VSIZE = 5;

class foobar {
public:
   foobar() { initialize(); };
   ~foobar() = default;

   static void foo();
   void bar();
private:
   void initialize() { bar(); };
   std::vector<std::vector<uint32_t>> vec1;
};

// This succeeds.
void foobar::foo() {
   std::vector<std::vector<uint32_t>> vec2;
   vec2.reserve(VSIZE);
   for(int i=0;i<VSIZE;i++){
      vec2[i].emplace_back(0);
   }
   std::cout << "Finished foo." << std::endl;
}

// This fails.
void foobar::bar() {

   // Reserve the needed memory for vec1.
   vec1.reserve(VSIZE);
   for(int i=0;i<VSIZE;i++){

      // Reserve the needed memory for each vector within vec1.
      vec1[i].reserve(VSIZE);
   }
   for(int i=0;i<VSIZE;i++){
      vec1[i].emplace_back(0);
   }
   std::cout << "Finished bar." << std::endl;
}

int main() {
   foobar::foo();
   foobar TC;
}

Вывод этого кода

Finished foo.
Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)

РЕДАКТИРОВАТЬ: Хорошо, так ... Мне придется разработать лучший минимальный пример, потому что я только что понял, основываясь на комментариях, что замена всех резервов с изменением размера прекрасно работает в этом коде. Они, однако, не работают в моем производственном коде, потому что я уже попробовал это и просто сделал снова. Мне придется выяснить, в чем дело, и изменить вопрос дальше.

Решение

РЕДАКТИРОВАТЬ 2: Новый день на работе, и после прочтения комментариев здесь мне удалось чтобы исправить мою проблему. Я оставил все резервы, кроме моих многомерных векторов. Моя проблема была решена с помощью изменения размера этих векторов и последующего резервирования их векторов. Таким образом, для приведенного выше случая я изменил бар, чтобы быть

void foobar::bar() {
   // Resize vec1 to allocate the needed storage.
   vec1.resize(VSIZE);
   for(int i=0;i<VSIZE;i++){

      // Reserve the needed memory for each vector within vec1.
      vec1[i].reserve(VSIZE);
   }
   for(int i=0;i<VSIZE;i++){
      vec1[i].emplace_back(0);
   }
   std::cout << "Finished bar." << std::endl;
}

1 Ответ

0 голосов
/ 04 марта 2020

Здесь происходит сумасшествие sh:

#0  0x0000555555556352 in __gnu_cxx::new_allocator<unsigned int>::construct<unsigned int, int> (this=0x55555556deb0, __p=0x0) at /usr/include/c++/9/ext/new_allocator.h:147
#1  0x0000555555555cd7 in std::allocator_traits<std::allocator<unsigned int> >::construct<unsigned int, int> (__a=..., __p=0x0) at /usr/include/c++/9/bits/alloc_traits.h:484
#2  0x000055555555582e in std::vector<unsigned int, std::allocator<unsigned int> >::emplace_back<int> (this=0x55555556deb0) at /usr/include/c++/9/bits/vector.tcc:115
#3  0x0000555555555367 in foobar::bar (this=0x7fffffffdcc0) at foo.cc:35
#4  0x00005555555554e8 in foobar::initialize (this=0x7fffffffdcc0) at foo.cc:14
#5  0x00005555555554ad in foobar::foobar (this=0x7fffffffdcc0) at foo.cc:8
#6  0x00005555555553b1 in main () at foo.cc:42

В кадре № 2:

#2  0x000055555555582e in std::vector<unsigned int, std::allocator<unsigned int> >::emplace_back<int> (this=0x55555556deb0) at /usr/include/c++/9/bits/vector.tcc:115
115         _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,

(gdb) p this->_M_impl._M_finish
$1 = (std::_Vector_base<unsigned int, std::allocator<unsigned int> >::pointer) 0x0

И это ваш ответ: хотя хранилище для элементов vec1[] зарезервировано, ни один из элементов еще не был построен.

Ваш код эквивалентен:

std::vector<int> *v = (std::vector<int> *) malloc(sizeof(*v));
v->emplace_back(0);

, и должно быть очевидно, почему это не работает.

...