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