【问题标题】:Why do I keep getting a segmentation fault with my delete function为什么我的删除功能总是出现分段错误
【发布时间】:2020-02-25 01:14:43
【问题描述】:

我有一个任务,我需要使用重载的析构函数来删除动态分配的指针。但是,当它运行时,我的一些指针被删除,直到我的一个对象的指针出现分段错误,一个指向“和第二个”,使用参数化构造函数。 我试图通过并确保删除运算符有括号(因为我的新运算符有)我通过打印出它的信息和地址来确保该对象仍然存在。我试图重写我的分配函数,并且我试图检查我的析构函数以查看它在哪里搞砸了。 如果有帮助,我已经包含了我的析构函数、分配函数、解除分配函数和参数化构造函数。

'''
//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;
    }

}

'''

【问题讨论】:

  • buffer_allocate 并不是捕捉异常然后返回void 的好地方。该程序将继续愉快地认为存储已分配,因为没有人告诉它做任何其他事情。打印到屏幕上的错误消息仅在程序尝试访问空指针但失败后对用户有用。
  • 你在关注rule of 3/5/0吗?
  • while(*strPtr) 循环实际上是strlen。无需在这里重新发明轮子。
  • buffer_allocate 中要注意的另一件事:如果m_buffer 已经指向分配怎么办?
  • 复制构造函数实现了吗?是否实现了赋值运算符?如果未实施,它们是否被明确删除?

标签: c++ segmentation-fault dynamic-memory-allocation delete-operator


【解决方案1】:

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);
}

附录:

您的班级可能违反了the Rule of Three。如果MyString 没有复制构造函数和赋值运算符与析构函数一起使用,任何有意或无意的副本都会将MyString 变成定时炸弹。其中一个副本的析构函数将在其他副本之前运行,而其他副本则没有有效的m_buffer

MyString::buffer_allocate 不能安全地返回 void,除非它允许传播异常。捕获bad_alloc 会使对象在m_buffer 处没有有效分配,并且程序的其余部分将不知道这一点。程序中的所有其他访问都必须测试有效缓冲区或参与未定义的行为以尝试访问无效内存。最好让异常通过并被程序的另一部分捕获,该部分更适合决定要做什么。

如果在MyString 上调用MyString::buffer_allocate,而m_buffer 已经有一个有效分配,MyString::buffer_allocate 将泄漏现有分配。我推荐一个

if (m_buffer) 
{
    delete[] m_buffer;
}

MyString的构造函数中将m_buffer初始化为null

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

【讨论】:

    【解决方案2】:

    所以我不得不将它重新制作为一些工作代码。 问题可能是字符串长度必须扩展为 1 以添加 nul 终止符。所以这使得:

    // 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();
    }
    

    【讨论】:

    • @user4581301 忘记了m_buffer 的默认分配。现在,如果new 抛出,它将保持nullptr
    猜你喜欢
    • 1970-01-01
    • 2018-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-25
    • 2011-12-22
    • 1970-01-01
    相关资源
    最近更新 更多