Почему я продолжаю получать ошибку сегментации с моей функцией удаления - PullRequest
1 голос
/ 29 октября 2019

У меня есть задание, в котором мне нужно использовать перегруженный деструктор для удаления динамически размещаемых указателей. Однако, когда он работает, некоторые из моих указателей удаляются до тех пор, пока не произойдет ошибка сегментации с одним из указателей моих объектов, один из которых указывает на «и второй», созданным с помощью параметризованного конструктора. Я попытался пройти и убедиться, что оператор удаления имеет квадратные скобки (потому что мой новый оператор сделал это). Я убедился, что объект все еще существует, распечатав его информацию и адрес. Я попытался переписать свою функцию распределения, и я попытался просмотреть свой деструктор, чтобы увидеть, где он не работает. Если это помогает, я включил мой деструктор, мою функцию выделения, мою функцию освобождения и мой параметризованный конструктор.

'''
//Destructor
MyString::~MyString()
{
  buffer_deallocate();
};

void MyString::buffer_deallocate() {
  cout << m_buffer << endl;
  delete[](m_buffer);
  m_buffer = NULL;
  m_size = 0;

}

void MyString::buffer_allocate(size_t size) {
  try {

    m_buffer = new char[size];
    m_size = size;
  }
  catch(bad_alloc&)
    {
      cout << "Errror: Unable to allocate memory" << endl;
      buffer_deallocate();
    }

}


//Parameterized Constructor
MyString::MyString(const char * str)
  :m_size(0)
{
  const char * strPtr = str;
  while(*strPtr)
    {
      strPtr++;
      m_size++;
    }

    buffer_allocate(m_size);

    for(int i = 0; i < m_size; i++)
      {
        m_buffer[i] = str[i];
      }

};
'''

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

Редактировать: я попробовал большинство из того, что было рекомендовано. По крайней мере, как я понял, проблема все еще сохраняется, и я понимаю, что теперь я немного разбирался в своем коде. (Пожалуйста, прости меня, я все еще учусь.) Вот новый код вместе с остальной частью файла функции для справки:

'''
#include<iostream>
#include<string.h>
using namespace std;

#include"MyString.h"


//Default Constructor
MyString::MyString()
:m_size(0), m_buffer(NULL)
{
        buffer_allocate(0);
};



//Parameterized Constructor
MyString::MyString(const char * str)
  :m_size(strlen(str)+1), m_buffer(NULL)
{
        buffer_allocate(m_size);
        strncpy(m_buffer, str, m_size);

};



//Copy Constructor
MyString::MyString(const MyString & other)
  :m_size(0), m_buffer(NULL)
{
  const char * otherPtr = other.c_str();
  buffer_allocate(other.size());

  for(int i = 0; i < size(); i++)
    {
      m_buffer[i] = otherPtr[i];
    }
        m_buffer[m_size] = '\0';
};


//Destructor
MyString::~MyString()
{
  buffer_deallocate();
};



size_t MyString::size() const
{
  return m_size;
}



size_t MyString::length() const{
  return m_size-1;
}



const char * MyString::c_str() const{
  return m_buffer;
}


bool MyString::operator==(const MyString & other) const {
  char * m_bufferPointer = m_buffer;
  while(*m_bufferPointer++)
    {
      const char * str_ptr = other.c_str();
      if(*m_buffer != *str_ptr++)
        {
          return 0;
        }
    }
  return 1;
}


MyString & MyString::operator=(const MyString & rhs) {
  buffer_deallocate();

  buffer_allocate(rhs.size());
  const char * c_strPtr = rhs.c_str();
  int i;
  for(i = 0; i < rhs.size(); i++)
    {
      this->m_buffer[i] = c_strPtr[i];
    }
  return *this;
}




MyString MyString::operator+ (const MyString & other_myStr) const {

  char * temp_pointer;
  temp_pointer;
  size_t temp_size = m_size + other_myStr.size();
  //New Combined Buffer for Concatanation
  try {
    temp_pointer = new char[temp_size];
    temp_pointer = strcat(this->m_buffer, other_myStr.c_str());

  }
  catch(bad_alloc&)
    {
      cout << "Error: Unable to Allocate Memory";
      return NULL;
    }
  return MyString(temp_pointer);
}



char & MyString:: operator[](size_t index) {
  return m_buffer[index];
}


const char & MyString::operator[] (size_t index) const {
  return m_buffer[index];
}


ostream & operator << (ostream& os, const MyString & myStr) {
  os << myStr.m_buffer;
  return os;

}

void MyString::buffer_deallocate() {



  cout << "Trying to delete : " <<m_buffer << endl;
        if(m_buffer){
                delete[](m_buffer);
        }
        cout << " Success" <<endl;
  m_buffer = NULL;
  m_size = 0;

}

void MyString::buffer_allocate(size_t size) {
        try {

    m_buffer = new char[size];
    m_size = size;
  }
  catch(bad_alloc&)
    {
      cout << "Errror: Unable to allocate memory" << endl;
        m_size = 0;
    }

}

'' '

Ответы [ 2 ]

0 голосов
/ 29 октября 2019

in MyString::buffer_deallocate

cout << m_buffer << endl;

требует, чтобы m_buffer был нулевым. К сожалению, MyString::MyString(const char * str) не дает такой гарантии.

Вы можете

for(int i = 0; i < m_size; i++)
{
    cout << m_buffer[i] << endl;
}

вместо того, чтобы печатать строку символ за символом, но, вероятно, более полезно тратить байт, нульзавершите работу и воспользуйтесь стандартной библиотекой

MyString::MyString(const char * str)
  :m_size(0)
{
  const char * strPtr = str;
  while(*strPtr)
    {
      strPtr++;
      m_size++;
    }

    buffer_allocate(m_size); 

    for(int i = 0; i < m_size; i++)
      {
        m_buffer[i] = str[i];
      }
    m_buffer[m_size] = '\0'; // add the null
}

, а затем

void MyString::buffer_allocate(size_t size) {
  try {

    m_buffer = new char[size+1]; // +1 for the null terminator
    m_size = size;
  }
  catch(bad_alloc&) // this is a bad thing to do here. More on that later.
    {
      cout << "Errror: Unable to allocate memory" << endl;
      buffer_deallocate();
    }

}

Но мы можем упростить это с помощью нескольких вызовов библиотечных функций.

MyString::MyString(const char * str)
  :m_size(strlen(str))
{
    buffer_allocate(m_size);
    strcpy(m_buffer, str);
}

Приложение:

Ваш класс может нарушать Правило трех . Если у MyString нет конструктора копий и оператор присваивания, чтобы идти вместе с деструктором, любые копии, намеренные или случайные, превратят MyString в бомбу замедленного действия. Деструктор одной из копий будет запущен до того, как остальные оставят остальные без действительного m_buffer.

MyString::buffer_allocate, не сможет безопасно вернуть void, если не разрешит распространение исключения. Поймав bad_alloc, вы оставите объект без действительного выделения на m_buffer, и остальная программа не узнает об этом. Любой другой доступ в программе должен проверять допустимый буфер или участвовать в неопределенном поведении, пытаясь получить доступ к недействительной памяти. Вероятно, лучше позволить исключению провалиться и быть пойманным другой частью программы, которая лучше подходит для принятия решения о том, что делать.

MyString::buffer_allocate приведет к утечке существующего выделения при вызове на MyString, который уже имеет действительное распределение на m_buffer. Я рекомендую

if (m_buffer) 
{
    delete[] m_buffer;
}

и инициализировать m_buffer в null в конструкторе MyString

MyString(const char* str)
    : m_size(std::strlen(str)), m_buffer(nullptr) 
{
    buffer_allocate(m_size);
    std::strncpy(m_buffer, str, m_size);
}
0 голосов
/ 29 октября 2019

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

// prevent some MSVS warnings->errors
#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <string>
#include <cstring>


//Destructor
class MyString {
private:
    size_t m_size;
    char* m_buffer;

    void buffer_allocate(size_t size) {
        try {
            m_buffer = new char[size];
            m_size = size;
        }
        catch (std::bad_alloc&)
        {
            std::cout << "Errror: Unable to allocate memory\n";
            // allocation failed, nothing changed, don't delete/
            m_size = 0;
        }

    }

    void buffer_deallocate() {
        // printing in the buffer deallocation??
        delete[] m_buffer;
        m_buffer = nullptr;
        m_size = 0;
    }

public:
    MyString(const char* str)
        : m_size(std::strlen(str)+1) // add null termination
        , m_buffer(nullptr)
    {
        buffer_allocate(m_size);
        std::strncpy(m_buffer, str, m_size);
    }

    ~MyString() {
        buffer_deallocate();
    }

    void Print() const {
        std::cout << m_buffer << '\n';
    }
};

int main() {
    std::string input{ "Hello World!" };
    MyString myString(input.c_str());
    myString.Print();
}
...