最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++深度探索運算符重載和返回值優(yōu)化

 更新時間:2022年04月24日 11:55:01   作者:小裘HUST  
這篇文章主要介紹了C++運算符重載及編譯器返回值優(yōu)化,C++當中除了函數(shù)可以重載之外,其實運算符也是可以重載的,下面一起來詳細了解吧

  今天遇到的是內(nèi)存釋放錯誤的問題。原因是沒寫拷貝構(gòu)造函數(shù),奇怪的是我之前也沒寫確實能正常工作的,今天深究了一下發(fā)現(xiàn)是編譯器做了返回值優(yōu)化。

問題背景

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

具體問題

  當類中有那種需要動態(tài)分配空間的成員的時候,要記得提醒自己重載拷貝構(gòu)造函數(shù)和賦值運算符,這兩者缺一不可。為了舉個例子,我定義了下面這個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類型的變量代表數(shù)據(jù)的個數(shù)。

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

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

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

  減法運算重載,返回值是一個類的對象。函數(shù)返回后,這個類的對象就已經(jīng)被析構(gòu)了,所以在它被析構(gòu)之前一般會先調(diào)用一個拷貝構(gòu)造函數(shù),將這個類的對象拷貝給一個新的臨時的對象。默認拷貝構(gòu)造函數(shù)采用淺拷貝,這在遇到類中包含指針類型的成員時很可能造成對同一塊內(nèi)存區(qū)域的重復釋放。所以我們需要重載拷貝構(gòu)造函數(shù),為指針成員申請新的內(nèi)存空間。

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

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

  有的編譯器就會對這樣的情況進行優(yōu)化,省略對拷貝構(gòu)造函數(shù)的調(diào)用,直接賦值。

  我今天遇到的問題是因為,我之前不知道在這個過程中會調(diào)用拷貝構(gòu)造函數(shù),所以沒有重寫拷貝構(gòu)造函數(shù)。意外的是,之前我這么做也是能用的,但我現(xiàn)在覺得不管怎樣還是得把拷貝構(gòu)造函數(shù)寫上,不能偷懶。

測試代碼

  為了便于驗證這一過程,我寫了一部分測試代碼,可以用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;
}

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

  上圖是在加上了“-fno-elide-constructors”編譯選項后的運行結(jié)果,可以看到執(zhí)行了兩次析構(gòu),對應(yīng)減法重載函數(shù)內(nèi)的對象和拷貝構(gòu)造函數(shù)生成的臨時對象被析構(gòu)。

  而沒有“-fno-elide-constructors”選項的時候,就只會有一次析構(gòu),因為沒有調(diào)用拷貝構(gòu)造函數(shù)。

  如果加了這個選項,但是沒有重寫拷貝構(gòu)造函數(shù),就會在第二次析構(gòu)的時候產(chǎn)生重復釋放內(nèi)存的問題。

到此這篇關(guān)于C++深度探索運算符重載和返回值優(yōu)化的文章就介紹到這了,更多相關(guān)C++運算符重載內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++的類型轉(zhuǎn)換(強轉(zhuǎn))你了解嗎

    C++的類型轉(zhuǎn)換(強轉(zhuǎn))你了解嗎

    這篇文章主要為大家詳細介紹了C++的類型轉(zhuǎn)換,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • C++ TensorflowLite模型驗證的過程詳解

    C++ TensorflowLite模型驗證的過程詳解

    這篇文章給大家介紹了C++ TensorflowLite模型驗證的過程,測試代碼,主要是RunInference()和read_file(),詳細操作過程跟隨小編一起看看吧
    2021-08-08
  • C++ const的各種用法詳解

    C++ const的各種用法詳解

    const名叫常量限定符,用來限定特定變量,以通知編譯器該變量是不可修改的。習慣性的使用const,可以避免在函數(shù)中對某些不應(yīng)修改的變量造成可能的改動。本文主要談?wù)刢onst的用法,感興趣的同學可以參考閱讀
    2023-04-04
  • C語言 枚舉類型(Enum)詳解及示例代碼

    C語言 枚舉類型(Enum)詳解及示例代碼

    本文主要介紹C語言 枚舉類型,這里提供了詳細的相關(guān)資料及示例代碼,以便大家學習參考,有興趣的小伙伴可以參考下
    2016-08-08
  • 詳解c++實現(xiàn)信號槽

    詳解c++實現(xiàn)信號槽

    這篇文章主要為大家介紹了c++實現(xiàn)信號槽,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2021-12-12
  • C++日期類的實現(xiàn)日期計算器舉例詳解

    C++日期類的實現(xiàn)日期計算器舉例詳解

    這篇文章主要給大家介紹了關(guān)于C++日期類實現(xiàn)日期計算器的相關(guān)資料,我們要考慮日期的增加和減少,自增和自減,以及兩個日期類的比較,以及當前日期類的日期顯示和用戶的輸入輸出,需要的朋友可以參考下
    2024-05-05
  • C++服務(wù)器和客戶端交互的項目實踐

    C++服務(wù)器和客戶端交互的項目實踐

    本文主要介紹了C++服務(wù)器和客戶端交互的項目實踐,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-07-07
  • C語言實現(xiàn)輸出1000以內(nèi)的所有完全數(shù)

    C語言實現(xiàn)輸出1000以內(nèi)的所有完全數(shù)

    這篇文章主要介紹了C語言實現(xiàn)輸出1000以內(nèi)的所有完全數(shù),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-06-06
  • C語言 makefile學習及實現(xiàn)實例

    C語言 makefile學習及實現(xiàn)實例

    這篇文章主要介紹了C語言 makefile學習及實現(xiàn)實例的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • Opencv實現(xiàn)最小外接矩形和圓

    Opencv實現(xiàn)最小外接矩形和圓

    這篇文章主要為大家詳細介紹了Opencv實現(xiàn)最小外接矩形和圓,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-05-05

最新評論

合肥市| 稷山县| 沅江市| 开化县| 安国市| 芦溪县| 龙口市| 六枝特区| 观塘区| 安义县| 西乡县| 婺源县| 惠水县| 南投市| 德化县| 宝应县| 盱眙县| 汨罗市| 海城市| 乌什县| 建瓯市| 台州市| 衡阳市| 江北区| 吴堡县| 泉州市| 北宁市| 达州市| 油尖旺区| 泰和县| 盖州市| 连城县| 日土县| 通榆县| 城口县| 蛟河市| 新竹市| 高唐县| 清水县| 涡阳县| 灌云县|