【十九】一些實際工程中的問題

1、Bug

  • 在實際工程中內存操作是bug的重要來源
  • C++將堆內存交由開發人員自由使用,因此
    • 未及時釋放,將產生內存泄漏
    • 重複釋放同一段內存,行爲未知
    • 使用越界,操作了不屬於自己的內存

思考:
怎樣最大限度的避開上述的使用問題?

2、數組類
內存越界的問題常發生於數組的使用中
解決方案:數組類

工程中,在非特殊情況下,要求開發者使用預先編寫的數組類對象代替C++語言中的原生數組,而其實C++中也已經提供了這樣的數組類!

數組類的自定義實現:

array.h

#ifndef _ARRAY_H_
#define _ARRAY_H_

template <typename T>
class Array
{
private:
  int     m_length;
  T*      m_pointer;

public:
  Array();
  Array(int length);
  Array(const Array<T>& obj);
  ~Array();

  int Length();
  T& operator[] (int i);
  Array<T>& operator= (const Array<T>& obj);
  bool operator== (const Array<T>& obj);
  bool operator!= (const Array<T>& obj);
};

#endif

array.hpp

#ifndef _ARRAY_DEF_H_
#define _ARRAY_DEF_H_

#include "array.h"


/*
* 構造函數
* 參  數:
*     無
* 返回值:
*     無
*/
template <typename T>
Array<T>::Array() : m_length(0),m_pointer(nullptr)
{

}


/*
* 構造函數
* 參  數:
*     數組長度,應該大於等於0的整數
* 返回值:
*     無
*/
template <typename T>
Array<T>::Array(int length) : m_length(0),m_pointer(nullptr)
{
  if(length < 0)
  {
    length = 0;
  }
  m_length = length;
  m_pointer = new T[m_length];
}


/*
* 拷貝構造函數
* 參  數:
*     被拷貝的對象引用
* 返回值:
*     無
*/
template <typename T>
Array<T>::Array(const Array<T>& obj): m_length(0),m_pointer(nullptr)
{
  m_length = obj.m_length;
  m_pointer = new T[m_length];
  if(m_pointer != nullptr)
  {
    for(int i = 0; i < m_length; i++)
    {
      m_pointer[i] = obj.m_pointer[i];
    }
  }
}


/*
* 析構函數
* 參  數:
*     無
* 返回值:
*     無
*/
template <typename T>
Array<T>::~Array()
{
  m_length = 0;
  if(m_pointer != nullptr)
  {
    delete[] m_pointer;
    m_pointer = nullptr;
  }
}

/*
* 獲取數組長度
* 參  數:
*     無
* 返回值:
*     返回數組長度,應該是一個非負值
*/
template <typename T>
int Array<T>::Length()
{
  return m_length;
}


/*
* 重載數組下標運算符,訪問數組元素
* 參  數:
*     要訪問的元素的下標
* 返回值:
*     返回該下標元素的引用
*/
template <typename T>
T& Array<T>::operator[] (int i)
{
  if(( 0 <= i ) && (i < m_length))
  {
    return m_pointer[i];
  }
  else
  {
    return m_pointer[0];
  }
}


/*
* 拷貝數組類
* 參  數:
*     被拷貝的數組對象的引用
* 返回值:
*     返回新對象的引用
*/
template <typename T>
Array<T>& Array<T>::operator= (const Array<T>& obj)
{
  if(m_pointer != nullptr)
  {
    delete[] m_pointer;
    m_pointer = nullptr;
  }
  m_length = obj.m_length;
  m_pointer = new T[m_length];
  if(m_pointer != nullptr)
  {
    for(int i = 0; i < m_length; i++)
    {
      m_pointer[i] = obj.m_pointer[i];
    }
  }
  return *this;
}


/*
* 判斷兩個數組是否相等
* 參  數:
*     數組對象的引用
* 返回值:
*     相等,返回true;不相等,返回false
*/
template <typename T>
bool Array<T>::operator== (const Array<T>& obj)
{
  bool ret = true;
  if(m_length == obj.m_length)
  {
    for(int i = 0; i < m_length; i++)
    {
      if(m_pointer[i] != obj.m_pointer[i])
      {
        ret = false;
        break;
      }
    }
  }
  else
  {
    ret = false;
  }
  return ret;
}

/*
* 判斷兩個數組是否不等
* 參  數:
*     數組對象的引用
* 返回值:
*     相等,返回false;不相等,返回true
*/
template <typename T>
bool Array<T>::operator!= (const Array<T>& obj)
{
  return !(*this == obj);
}


#endif

main.cpp

#include <iostream>
#include "array.hpp"
using namespace std;


int main()
{
  Array<double> ab(5);
  for(int i = 0; i < ab.Length(); i++)
  {
    ab[i] = i * 0.1 + 0.1;
    cout << "ab["<< i << "] = " << ab[i] << '\t';
  }
  cout << endl;

  Array<double> ac(5);
  for(int i = 0; i < ac.Length(); i++)
  {
    ac[i] = i * 0.1 + 0.1;
    cout << "ac["<< i << "] = " << ac[i] << '\t';
  }
  cout << endl;

  Array<double> ad = ac;    //拷貝構造函數

  if(ad != ac)
  {
    cout << "ad != ac" << endl;
  }
  else
  {
    cout << "ad == ac" << endl;
  }
  for(int i = 0; i < ad.Length(); i++)
  {
    ad[i] = i + 1;
    cout << "ad["<< i << "] = " << ad[i] << '\t';
  }
  cout << endl;

  Array<double> ae;
  ae = ad;    //拷貝對象

  for(int i = 0; i < ae.Length(); i++)
  {
    ae[i] = i + 1;
    cout << "ae["<< i << "] = " << ae[i] << '\t';
  }
  cout << endl;

  return 0;
}

以上代碼,僅僅是對C++內置數組類實現的一個模擬和猜想!

3、智能指針

內存泄漏和內存多次釋放常發生於指針的使用過程中

解決方案:智能指針

工程中,要求開發者使用預先編寫的智能指針類對象代替C語言中的原生指針!

什麼是智能指針?

工程中的智能指針是一個類模板

  • 通過構造函數接管申請的堆內存
  • 通過析構函數確保堆內存被及時釋放
  • 通過重載指針運算符* 和->模擬指針的行爲
  • 通過重載比較運算符== 和 != 模擬指針的比較

以下智能指針類結合了引用計數機制進行內存的釋放!

smartpointer.h

#ifndef _SMARTPOINTER_H_
#define _SMARTPOINTER_H_

template <typename T>
class SmartPointer
{
private:
  int*  m_refcount;
  T*    m_pointer;

public:
  SmartPointer();
  SmartPointer(const T* pointer);
  SmartPointer(const SmartPointer<T>& obj);
  ~SmartPointer();
  T& operator* ();
  T* operator-> ();
  SmartPointer<T>& operator= (const SmartPointer<T>& obj);
  bool operator== (const SmartPointer<T>& obj);
  bool operator!= (const SmartPointer<T>& obj);

  int GetrefCount();
private:
  void IncrefCount();
  void DecrefCount();
};


#endif

smartpoint.hpp

#ifndef _SMARTPOINTER_DEF_H_
#define _SMARTPOINTER_DEF_H_
#include <iostream>
using namespace std;
#include "smartpointer.h"

/*
* 獲取當前對象引用計數數值
* 參  數:
      無
* 返回值:
      如果成功,返回非負數,失敗返回-1
*/
template <typename T>
int SmartPointer<T>::GetrefCount()
{
  if(m_refcount != nullptr)
  {
    return *m_refcount;
  }
  else
  {
    return -1;
  }
}


/*
* 增加當前對象引用計數數值,+1
* 參  數:
      無
* 返回值:
      無
*/
template <typename T>
void SmartPointer<T>::IncrefCount()
{
  if(m_refcount != nullptr)
  {
    ++(*m_refcount);
  }
}


/*
* 減小當前對象引用計數數值,-1
* 參  數:
      無
* 返回值:
      無
*/
template <typename T>
void SmartPointer<T>::DecrefCount()
{
  if(m_refcount != nullptr)
  {
    --(*m_refcount);
  }
}

/*
* 構造函數
* 參  數:
      無
* 返回值:
      無
*/
template <typename T>
SmartPointer<T>::SmartPointer() : m_refcount(nullptr), m_pointer(nullptr)
{

}

/*
* 構造函數
* 參  數:
      指向的堆地址
* 返回值:
      無
*/
template <typename T>
SmartPointer<T>::SmartPointer(const T* pointer) : m_refcount(nullptr), m_pointer(nullptr)
{
  m_pointer = const_cast<T*>(pointer);
  if(m_pointer != nullptr)
  {
    if(m_refcount == nullptr)
    {
      m_refcount = new int(1);
    }
  }
}

/*
* 拷貝構造函數
* 參  數:
      一個SmartPointer<T>對象的引用
* 返回值:
      無
*/
template <typename T>
SmartPointer<T>::SmartPointer(const SmartPointer<T>& obj): m_refcount(nullptr), m_pointer(nullptr)
{
  m_pointer = obj.m_pointer;
  m_refcount = obj.m_refcount;
  IncrefCount();
}


/*
* 析構函數
* 參  數:
      無
* 返回值:
      無
*/
template <typename T>
SmartPointer<T>::~SmartPointer()
{
  if(m_pointer != nullptr)
  {
    DecrefCount();
    if(GetrefCount() <= 0)
    {
      delete m_pointer;
      m_pointer = nullptr;
      delete m_refcount;
      m_refcount = nullptr;
    }
  }
}


/*
* 重載解引用操作符
* 參  數:
      無
* 返回值:
      該對象所指地址空間對象的引用
*/
template <typename T>
T& SmartPointer<T>::operator* ()
{
  return *m_pointer;
}


/*
* 重載指針成員操作符
* 參  數:
      無
* 返回值:
      該對象所指地址空間指針
*/
template <typename T>
T* SmartPointer<T>::operator-> ()
{
  return m_pointer;
}

/*
* 重載賦值運算符
* 參  數:
      一個SmartPointer<T>對象的引用
* 返回值:
      該對象本身的引用
*/
template <typename T>
SmartPointer<T>& SmartPointer<T>::operator= (const SmartPointer<T>& obj)
{
  this->~SmartPointer();

  m_pointer = obj.m_pointer;
  m_refcount = obj.m_refcount;
  IncrefCount();
  return *this;
}


/*
* 重載比較運算符==
* 參  數:
      一個SmartPointer<T>對象的引用
* 返回值:
      如果相等,返回true;不等,返回false;
*/
template <typename T>
bool SmartPointer<T>::operator== (const SmartPointer<T>& obj)
{
  if(m_pointer == obj.m_pointer)
  {
    return true;
  }
  else
  {
    return false;
  }
}


/*
* 重載比較運算符!=
* 參  數:
      一個SmartPointer<T>對象的引用
* 返回值:
      如果不相等,返回true;相等,返回false;
*/
template <typename T>
bool SmartPointer<T>::operator!= (const SmartPointer<T>& obj)
{
  return !(*this == obj);
}


#endif

main.cpp

#include <iostream>
#include "smartpointer.hpp"

using namespace std;

class Student
{
public:
  const char*   Name;
  int     Age;

public:
  Student(const char* str, int age)
  {
    Name = str;
    Age = age;
  }
};

void func()
{
  SmartPointer<int> pi = new int(5);
  cout << "pi.refcount = "<< pi.GetrefCount() << endl;

  SmartPointer<int> pii;
  pii = pi;
  cout << "pi.refcount = "<< pi.GetrefCount() << endl;

  SmartPointer<int> pt = new int(100);
  cout <<"pt.refcount = "<< pt.GetrefCount() << endl;

  pi = pt;
  cout << "pii.refcount = "<< pii.GetrefCount() << endl;
  cout <<"pt.refcount = "<< pt.GetrefCount() << endl;

  if(pi == pii)
  {
    cout << "pi == pii" << endl;
  }
  else
  {
    cout << "pi != pii" << endl;
  }

  SmartPointer<Student> stu = new Student("Tom",20);
  cout << "Name = " << stu->Name << '\t' << "Age = " << stu->Age << endl;
}

int main()
{
  func();
  return 0;
}
發佈了123 篇原創文章 · 獲贊 12 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章