Segfault с std :: vector = -операцией в неинициализированное пространство - PullRequest
0 голосов
/ 11 сентября 2018

Я получаю ошибки сегментации, когда использую оператор = -o для копирования структуры, содержащей std :: vector, в неинициализированную память. Критический код выглядит так:

template<typename T>
ComponentContainer
{
  T* buffer;
  size_t capacity;
  size_t m_size;

public:

  ComponentContainer();
  ~ComponentContainer();
  size_t size();
  void resize(size_t size);
  T & operator[](size_t index);
};

template<typename T>
void ComponentContainer<T>::resize(size_t newSize)
{
  if(this->m_size >= newSize)
  {
    this->m_size = newSize;
  }
  else
  {
    if(this->capacity < newSize)
    {
      const size_t newCapacity = capacity*2;
      T* newBuffer = (T*)malloc(newCapacity*sizeof(T));
      for(size_t i = 0; i<m_size; i++)
      {
        // checks if this->buffer[i] is valid intialized memory
        if(pseudo_checkIfElementIsInitialized(i))
        {
          // when this is uncommented no segfault happens
          //new (&newBuffer[i]) T(); 
          newBuffer[i] = this->buffer[i]; // <- segfault happens here 
        }
      }
      this->capacity = newCapacity;
      free(this->buffer);
      this->buffer = newBuffer;
    }
    this->m_size = newSize;
  }
}

T -тип - это структура с std :: vector структур, когда я получаю segfault. Я подозреваю, что std :: vector = -operator каким-то образом использует левую переменную newBuffer[i], и происходит ошибка сегментации, поскольку newBuffer[i] не инициализируется.

Объекты будут создаваться только при новом размещении с функцией T & operator[](size_t index). Malloc должен только распределять память, ничего не инициализируя.

Я пытался написать простой пример, но он не удался:

#include <iostream>
#include <vector>


struct Hello
{
    Hello()
    {
        std::cout << "constructor" << std::endl;
    }
    ~Hello()
    {
        std::cout << "destructor" << std::endl;
    }
    std::vector<double> v = std::vector<double>(1);
};


int main()
{
    Hello* buffer = (Hello*)malloc(1*sizeof(Hello));
    char* noise = (char*)buffer;
    for(size_t i = 0; i<sizeof(Hello); i++)
    {
        noise[i] = 100;
    }
    auto tmp = Hello();
    tmp.v[0] = 6.6;
    //new (&buffer[0]) Hello();
    buffer[0] = tmp;
    std::cout << buffer[0].v[0] << std::endl;

    return 0;
}

Работает нормально, без segfault. Я предполагаю, что это потому, что неинициализированная память была просто случайной для операции std :: vector = -o.

Итак

а) верна ли эта теория

и если да

б) как решить эту проблему без использования конструктора по умолчанию (T()) для каждого класса, который я использую в качестве T для моего ComponentContainer

1 Ответ

0 голосов
/ 11 сентября 2018

Ну да. Вы не можете присвоить объекту, который не существует.

Раскомментируйте строку, которая это исправляет!

Если вы не можете создать конструкцию по умолчанию, скопируйте конструкцию:

new (&newBuffer[i]) T(this->buffer[i]);

И если вы не можете этого сделать, тогда, ну, вы знаете все остальное.


Маллок должен выделять память только без инициализации.

Возможно ли, что вы недооценили вес этого утверждения? Вы не просто получаете память, а затем решаете, инициализировать ли ее некоторыми значениями. Вы должны на самом деле создавать объекты перед их использованием; это не обязательно. Вы программируете на C ++, а не манипулируете битами и байтами на ленте:)

...