一步一步重構柔性數組和智能指針

在C/C++實際工程開發中內存操作,稍不留神就會出現千奇百怪的各種bug,導致整個項目組花很大的時間使用各種工具定位錯誤,解決內存操作問題!

對於用戶使用Android手機,用了你開發的APP,非常鬱悶怎麼就越來越慢的困惑,在本章中我不會講用valgrind工具還是火焰圖等其他工具來定位你的問題的位置。我會重點用C/C++說明以下幾點如何預防?

1、防止數組越界操作,使用柔性數組;

2、內存泄露和多次釋放,使用智能指針;

當然你會說還需要注意使用malloc申請了內存後,應該立即檢查指針值是否爲NULL,防止使用值爲NULL的指針;動態申請操作必須和釋放操作匹配;free指針之後必須立即賦值爲NULL,防止野指針等等。有些是習慣問題,如果你注意到了,這都不是問題!

柔性數組是數組大小待定的數組,通過結構體將成員的結構用malloc ()函數進行內存的動態分配,並且分配的內存應該大於結構的大小,以適應柔性數組的預期大小,防止數組越界的問題。

C語言實現:

#include <stdio.h>
#include <malloc.h>

typedef struct _soft_array
{
    int len;
    int array[];
}SoftArray;

int main(int argc, char **argv)
{  
    int i = 0;
    SoftArray* sa = (SoftArray*)malloc(sizeof(SoftArray) + sizeof(int) * 5);
    
    sa->len = 5;
    
    for(i=0; i<sa->len; i++)
    {
        sa->array[i] = i + 1;
    }
    
    for(i=0; i<sa->len; i++)
    {
        printf("sa->array[%d] = %d\n", i,sa->array[i]);   
    }
    
    free(sa);
    
    return 0;
}

C++實現:

#include <stdio.h>
#include "Array.h"

int main(int argc, char **argv)
{
    Array a1(5);
    Array a2(0);
    
    if( a1 != a2 )
    {
        printf("a1 != a2\n");
    }
    
    for(int i=0; i<a1.length(); i++)
    {
        a1[i] = i + 1;
    }
    
    for(int i=0; i<a1.length(); i++)
    {
        printf("Element %d: %d\n", i, a1[i]);
    }
    
    a2 = a1;
    
    if( a1 == a2 )
    {
        printf("a1 == a2\n");
    }
    
    for(int i=0; i<a2.length(); i++)
    {
        printf("Element %d: %d\n", i, a2[i]);
    }
    
    return 0;
}
#ifndef _ARRAY_H_
#define _ARRAY_H_

class Array
{
private:
    int mLength;
    int* mSpace;

public:
    Array(int length);
    Array(const Array& obj);//拷貝構造函數
    int length();
    ~Array();//析構函數
    int& operator[](int i);
    Array& operator= (const Array& obj);
    bool operator== (const Array& obj);//操作符重載
    bool operator!= (const Array& obj);
};

#endif
#include <stdio.h>
#include "Array.h"

Array::Array(int length)
{
    if( length < 0 )
    {
        length = 0;
    }
    
    mLength = length;
    mSpace = new int[mLength];
}

Array::Array(const Array& obj)
{
    mLength = obj.mLength;   
    mSpace = new int[mLength];
    
    for(int i=0; i<mLength; i++)
    {
        mSpace[i] = obj.mSpace[i];
    }
}

int Array::length()
{
    return mLength;
}

Array::~Array()
{
    mLength = -1;
    printf("~Array = %08X\n", mSpace);
    delete[] mSpace;
}

int& Array::operator[](int i)
{
    return mSpace[i];
}

Array& Array::operator= (const Array& obj)
{
    delete[] mSpace;
    
    mLength = obj.mLength;
    
    mSpace = new int[mLength];
    
    for(int i=0; i<mLength; i++)
    {
        mSpace[i] = obj.mSpace[i];
    }
    
    return *this;
}

bool Array::operator== (const Array& obj)
{
    bool ret = true;
    
    if( mLength == obj.mLength )
    {
        for(int i=0; i<mLength; i++)
        {
            if( mSpace[i] != obj.mSpace[i] )
            {
                ret = false;
                break;
            }
        }
    }
    else
    {
        ret = false;
    }
    
    return ret;
}

bool Array::operator!= (const Array& obj)
{
    return !(*this == obj);
}

不好不好,我需要一個通用的模板啊!好吧,你可以使用類模板來實現:

//柔性數組 類模板
#include <cstdlib>
#include <iostream>
#include "Array.hpp"

using namespace std;

int main(int argc, char *argv[])
{
    Array<int> ai(5);
    
    for(int i=0; i<ai.length(); i++)
    {
        ai[i] = i + 1;
    }
    
    for(int i=0; i<ai.length(); i++)
    {
        cout<<ai[i]<<endl;
    }
    
    Array<double> ad(6);
    
    for(int i=0; i<ad.length(); i++)
    {
        ad[i] = (i + 1) / 10.0;
    }
    
    for(int i=0; i<ad.length(); i++)
    {
        cout<<ad[i]<<endl;
    }
    
    return 0;
}
#ifndef _ARRAY_H_
#define _ARRAY_H_

template<typename T>
class Array
{
private:
    int mLength;
    T* mSpace;

public:
    Array(int length);
    Array(const Array& obj);//拷貝構造函數
    int length();//獲取數組長度
    ~Array();//析構函數
    T& operator[](int i);// 重載數組下標運算符,訪問數組元素
    Array& operator= (const Array& obj);//拷貝數組類
    bool operator== (const Array& obj);//判斷兩個數組是否相等
    bool operator!= (const Array& obj);//判斷兩個數組是否不等
};

#endif
#ifndef _ARRAY_DEF_H_
#define _ARRAY_DEF_H_

#include "Array.h"

template<typename T>
Array<T>::Array(int length)
{
    if( length < 0 )
    {
        length = 0;
    }
    
    mLength = length;
    mSpace = new T[mLength];
}

template<typename T>
Array<T>::Array(const Array& obj)
{
    mLength = obj.mLength;
    
    mSpace = new int[mLength];
    
    for(int i=0; i<mLength; i++)
    {
        mSpace[i] = obj.mSpace[i];
    }
}

template<typename T>
int Array<T>::length()
{
    return mLength;
}

template<typename T>
Array<T>::~Array()
{
    mLength = -1;
    
    delete[] mSpace;
}

template<typename T>
T& Array<T>::operator[](int i)
{
    return mSpace[i];
}

template<typename T>
Array<T>& Array<T>::operator= (const Array<T>& obj)
{
    delete[] mSpace;
    
    mLength = obj.mLength;
    
    mSpace = new int[mLength];
    
    for(int i=0; i<mLength; i++)
    {
        mSpace[i] = obj.mSpace[i];
    }
    
    return *this;
}

template<typename T>
bool Array<T>::operator== (const Array<T>& obj)
{
    bool ret = true;
    
    if( mLength == obj.mLength )
    {
        for(int i=0; i<mLength; i++)
        {
            if( mSpace[i] != obj.mSpace[i] )
            {
                ret = false;
                break;
            }
        }
    }
    else
    {
        ret = false;
    }
    
    return ret;
}

template<typename T>
bool Array<T>::operator!= (const Array& obj)
{
    return !(*this == obj);
}

#endif

在編寫大型程序的時候,有時我們忘記delete分配的內存,或者多次釋放分配的內存,這樣會造成內存泄露和程序的down機。在程序開發中,預先編寫智能指針類代替原生的指針。出現問題後直接返回錯誤。

通過類模板實現的步驟:

(1)構造函數接管內存的申請;

(2)析構函數確保內存被及時釋放;

(3)重載指針運算符*和->模擬指針的行爲;

(4)重載比較運算符== 和 != 模擬指針的比較。

//功能:智能指針
#include <stdio.h>
#include <cstdlib>
#include <iostream>
#include "SmartPointer.hpp"
using namespace std;

class Test
{
public:
    int i;
    void print()
    {
        cout<<i<<endl;
    }
};

int main(int argc, char *argv[])
{
	//構造函數 SmartPointer<int> pi (new int(5));
    SmartPointer<int> pi = new int(5);
    SmartPointer<Test> pt = new Test();
	SmartPointer<int> pj = pi;
    
    cout<<*pi<<endl;
    
    *pi = 6;//使用重載操作符 
    
    cout<<*pi<<endl;
    
    pt->i = 7;
    pt->print();
	
	//使用重載操作符 
	if(pi == pj)
	{
		cout<<"=="<<endl;		
	}else{
		cout<<"!="<<endl;
	}
    
    return 0;
}
//智能指針 類定義 頭文件 SmartPoint.h
#ifndef _SMARTPOINTER_H_
#define _SMARTPOINTER_H_
//類模板
template<typename T>
class SmartPointer
{
protected:
    T* m_pointer;
public:
    SmartPointer();//構造函數
    SmartPointer(const T* pointer);//拷貝構造函數 
    ~SmartPointer();//析構函數
    T* operator->();//操作符重載
    T& operator*();
	bool operator==(const SmartPointer<T>& operater);
    bool operator!=(const SmartPointer<T>& operater);
};

#endif
//智能指針 類成員函數定義 頭文件 SmartPoint.hpp
#ifndef _SMARTPOINTER_DEF_H_
#define _SMARTPOINTER_DEF_H_

#include "SmartPointer.h"

template<typename T>
SmartPointer<T>::SmartPointer() 
{
    m_pointer = NULL;
}

template<typename T>
SmartPointer<T>::SmartPointer(const T* pointer)
{
    m_pointer = const_cast<T*>(pointer);
}

template<typename T>
SmartPointer<T>::~SmartPointer()
{
    delete m_pointer;
}

template<typename T>
T* SmartPointer<T>::operator->()
{
    return m_pointer;
}

template<typename T>
T& SmartPointer<T>::operator*()
{
    return *m_pointer;    
} 

template<typename T>
bool SmartPointer<T>::operator==(const SmartPointer<T>& operater)
{
    return m_pointer == operater.m_pointer;
}

template<typename T>
bool SmartPointer<T>::operator!=(const SmartPointer<T>& operater)
{
    return m_pointer != operater.m_pointer;
}  

#endif


下載

https://download.csdn.net/download/u010872301/10432433

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章