亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C++運算符重載和返回值優化的方法

發布時間:2022-04-24 14:16:39 來源:億速云 閱讀:153 作者:iii 欄目:開發技術

本篇內容介紹了“C++運算符重載和返回值優化的方法”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

問題背景

  編譯環境還是針對C6455 DSP,為了做一些簡單的圖像直方圖的處理,并且盡可能不用模板類,我自己寫了一個簡單的類用來存放帶長度信息的數組,并且可以做一些簡單的運算。重載了減法運算符,從而可以對兩個直方圖求差。

具體問題

  當類中有那種需要動態分配空間的成員的時候,要記得提醒自己重載拷貝構造函數和賦值運算符,這兩者缺一不可。為了舉個例子,我定義了下面這個CData類。

class CData
{
private:
    int *m_pData;
    unsigned int m_nLen;
public:
    CData();
    CData(unsigned int nLen);
    /* There is no copy constructor at the very begining */
    CData(const CData &data);
    ~CData();
    int &at(unsigned int i);
    int &at(unsigned int i) const;
    CData operator-(const CData &data);
    CData &operator=(const CData &data);
    CData &operator-=(const CData &data);
};

  在CData中,有兩個成員,分別是一個int類型的指針和一個unsigned int類型的變量代表數據的個數。

  我重載了一個減法運算符,為的是將兩個CData類型的數據長度相同的對象中的每個對應位置的int類型數據直接相減。而在調用減法運算的時候勢必會用到拷貝構造函數和賦值運算符,因此也需要對它們重載。

  順帶一提的是,在上面我還聲明了一個“-=”運算符的重載,為的是突出“-=”在一定場合會更加高效,但因為我在實際應用中不能直接覆蓋“被減數”中的數據,所以不能用“-=”運算符,只能通過減法運算符來實現。

CData CData::operator-(const CData &data)
{
    cout << "entering subtract" << endl;
    assert(m_nLen == data.m_nLen);
    CData ret(data.m_nLen);
    for (int i = 0; i < m_nLen; i++){
        ret.at(i) = at(i) - data.at(i);
    }
    return ret;
}

&emsp;&emsp;減法運算重載,返回值是一個類的對象。函數返回后,這個類的對象就已經被析構了,所以在它被析構之前一般會先調用一個拷貝構造函數,將這個類的對象拷貝給一個新的臨時的對象。默認拷貝構造函數采用淺拷貝,這在遇到類中包含指針類型的成員時很可能造成對同一塊內存區域的重復釋放。所以我們需要重載拷貝構造函數,為指針成員申請新的內存空間。

CData CData::&operator=(const CData &data)
{
    cout << "entering assign" << endl;
    assert(m_nLen == data.m_nLen);
    for (int i = 0; i < m_nLen; i++)
        at(i) = data.at(i);
    return *this;
}

&emsp;&emsp;減法運算返回的臨時對象如果不給新的對象接收,它就沒了。所以我們還需要重載賦值運算符,用來接收這個臨時對象中的數據,這一臨時對象被接收后,也會被析構。分析整個過程可以看到,從減法運算返回的類對象,其中的數據先要被復制到一個臨時對象里,再要從臨時對象復制到真正的賦值目標對象里,浪費了很多時間。

&emsp;&emsp;有的編譯器就會對這樣的情況進行優化,省略對拷貝構造函數的調用,直接賦值。

&emsp;&emsp;我今天遇到的問題是因為,我之前不知道在這個過程中會調用拷貝構造函數,所以沒有重寫拷貝構造函數。意外的是,之前我這么做也是能用的,但我現在覺得不管怎樣還是得把拷貝構造函數寫上,不能偷懶。

測試代碼

&emsp;&emsp;為了便于驗證這一過程,我寫了一部分測試代碼,可以用g++編譯。

#include <assert.h>
#include <iostream>
using namespace std;
class CData
{
private:
    int *m_pData;
    unsigned int m_nLen;
public:
    CData(): m_nLen(0), m_pData(nullptr)
    {
        cout << "construct without arg" << endl;
    }
    CData(unsigned int nLen): m_nLen(nLen)
    {
        cout << "construct with arg" << endl;
        m_pData = new int[nLen];
        assert(m_pData != NULL);
    }
    CData(const CData &data)
    {
        cout << "copy construct" << endl;
        m_nLen = data.m_nLen;
        m_pData = new int[data.m_nLen];
        assert(m_pData != nullptr);
        for (int i = 0; i < m_nLen; i++){
            at(i) = data.at(i);
        }
    }
    ~CData()
    {
        cout << "destruct" << endl;
        if(m_pData){
            delete[] m_pData;
            m_pData = nullptr;
        }
    }
    int &at(unsigned int i)
    {
        assert(i < m_nLen);
        return *(m_pData + i);
    }
    int &at(unsigned int i) const
    {
        assert(i < m_nLen);
        return *(m_pData + i);
    }
    CData operator-(const CData &data)
    {
        cout << "entering subtract" << endl;
        assert(m_nLen == data.m_nLen);
        CData ret(data.m_nLen);
        for (int i = 0; i < m_nLen; i++){
            ret.at(i) = at(i) - data.at(i);
        }
        return ret;
    }
    CData &operator=(const CData &data)
    {
        cout << "entering assign" << endl;
        assert(m_nLen == data.m_nLen);
        for (int i = 0; i < m_nLen; i++)
            at(i) = data.at(i);
        return *this;
    }
    CData &operator-=(const CData &data)
    {
        cout << "entering subtract and assign" << endl;
        assert(m_nLen == data.m_nLen);
        for (int i = 0; i < m_nLen; i++)
            at(i) -= data.at(i);
        return *this;
    }
};
int main()
{
    cout << "---------- start construct ----------" << endl;
    CData dataA(10);
    CData dataB(10);
    CData dataC(10);
    cout << "---------- start subtract ----------" << endl;
    dataC = dataA - dataB;
    cout << "---------- start subtract and assign ----------" << endl;
    dataA -= dataB;
    cout << "---------- end of program ----------" << endl;
    return 0;
}

&emsp;&emsp;g++編譯的程序,返回類對象的時候,默認是會省略拷貝構造函數的,加上“-fno-elide-constructors”的編譯選項后可以讓它不省略。

C++運算符重載和返回值優化的方法

&emsp;&emsp;上圖是在加上了“-fno-elide-constructors”編譯選項后的運行結果,可以看到執行了兩次析構,對應減法重載函數內的對象和拷貝構造函數生成的臨時對象被析構。

C++運算符重載和返回值優化的方法

&emsp;&emsp;而沒有“-fno-elide-constructors”選項的時候,就只會有一次析構,因為沒有調用拷貝構造函數。

C++運算符重載和返回值優化的方法

如果加了這個選項,但是沒有重寫拷貝構造函數,就會在第二次析構的時候產生重復釋放內存的問題。

“C++運算符重載和返回值優化的方法”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

c++
AI

永德县| 府谷县| 从江县| 林甸县| 沈丘县| 定边县| 峨边| 芷江| 耿马| 新建县| 阳高县| 安新县| 集贤县| 莎车县| 区。| 新安县| 奇台县| 原阳县| 凤庆县| 保德县| 济南市| 尼木县| 清水县| 南和县| 桦南县| 乾安县| 宣城市| 惠东县| 丰都县| 鸡泽县| 西贡区| 梁河县| 镇康县| 阳西县| 济源市| 富源县| 上蔡县| 沁水县| 沙湾县| 重庆市| 濮阳县|