亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

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

問(wèn)題背景

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

具體問(wèn)題

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

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

  順帶一提的是,在上面我還聲明了一個(gè)“-=”運(yùn)算符的重載,為的是突出“-=”在一定場(chǎng)合會(huì)更加高效,但因?yàn)槲以趯?shí)際應(yīng)用中不能直接覆蓋“被減數(shù)”中的數(shù)據(jù),所以不能用“-=”運(yùn)算符,只能通過(guò)減法運(yùn)算符來(lái)實(shí)現(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;
}

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

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

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

  我今天遇到的問(wèn)題是因?yàn)椋抑安恢涝谶@個(gè)過(guò)程中會(huì)調(diào)用拷貝構(gòu)造函數(shù),所以沒(méi)有重寫拷貝構(gòu)造函數(shù)。意外的是,之前我這么做也是能用的,但我現(xiàn)在覺(jué)得不管怎樣還是得把拷貝構(gòu)造函數(shù)寫上,不能偷懶。

測(cè)試代碼

  為了便于驗(yàn)證這一過(guò)程,我寫了一部分測(cè)試代碼,可以用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++編譯的程序,返回類對(duì)象的時(shí)候,默認(rèn)是會(huì)省略拷貝構(gòu)造函數(shù)的,加上“-fno-elide-constructors”的編譯選項(xiàng)后可以讓它不省略。

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

  而沒(méi)有“-fno-elide-constructors”選項(xiàng)的時(shí)候,就只會(huì)有一次析構(gòu),因?yàn)闆](méi)有調(diào)用拷貝構(gòu)造函數(shù)。

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

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

相關(guān)文章

  • C?C++輸入輸出基礎(chǔ)教程示例詳解

    C?C++輸入輸出基礎(chǔ)教程示例詳解

    當(dāng)我們?cè)诰W(wǎng)站做題的時(shí)候經(jīng)常會(huì)遇到各種要求的輸入輸出,而且會(huì)有時(shí)間超限等多個(gè)問(wèn)題,這時(shí)我們就要優(yōu)化我們的輸入輸出或者規(guī)范我們的輸入輸出格式,下面介紹C和C++中的輸入輸出問(wèn)題,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2023-11-11
  • C++小知識(shí):大于0并不意味著等于1

    C++小知識(shí):大于0并不意味著等于1

    今天小編就為大家分享一篇關(guān)于C++小知識(shí):大于0并不意味著等于1,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-01-01
  • C++實(shí)現(xiàn)比特幣系統(tǒng)的源碼

    C++實(shí)現(xiàn)比特幣系統(tǒng)的源碼

    這篇文章主要介紹了C++實(shí)現(xiàn)比特幣系統(tǒng)的源碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • C++ string.erase()用法詳解

    C++ string.erase()用法詳解

    這篇文章主要介紹了C++ string.erase()用法詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-09-09
  • 深入分析C++模板特化與偏特化

    深入分析C++模板特化與偏特化

    這篇文章主要介紹了C++模板特化與偏特化的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)c++,感興趣的朋友可以了解下
    2020-08-08
  • C++控制臺(tái)實(shí)現(xiàn)簡(jiǎn)單注冊(cè)登錄

    C++控制臺(tái)實(shí)現(xiàn)簡(jiǎn)單注冊(cè)登錄

    這篇文章主要為大家詳細(xì)介紹了C++控制臺(tái)實(shí)現(xiàn)簡(jiǎn)單注冊(cè)登錄,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-12-12
  • c++實(shí)現(xiàn)二路歸并排序的示例代碼

    c++實(shí)現(xiàn)二路歸并排序的示例代碼

    這篇文章主要介紹了c++實(shí)現(xiàn)二路歸并排序的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • 使用C# 判斷給定大數(shù)是否為質(zhì)數(shù)的詳解

    使用C# 判斷給定大數(shù)是否為質(zhì)數(shù)的詳解

    本篇文章是對(duì)使用C#判斷給定大數(shù)是否為質(zhì)數(shù)的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C++ OpenCV實(shí)現(xiàn)圖像修復(fù)功能

    C++ OpenCV實(shí)現(xiàn)圖像修復(fù)功能

    這篇文章主要介紹了通過(guò)C++ OpenCV中提供的inpaint API實(shí)現(xiàn)對(duì)有瑕疵的圖像進(jìn)行修復(fù),文中的方法講解詳細(xì),感興趣的同學(xué)可以跟隨小編一起學(xué)習(xí)一下
    2022-01-01
  • QT應(yīng)用啟動(dòng)失敗排查方法小結(jié)

    QT應(yīng)用啟動(dòng)失敗排查方法小結(jié)

    啟動(dòng)QT應(yīng)用經(jīng)常會(huì)碰到應(yīng)用啟動(dòng)失敗,qt platform plugin無(wú)法啟動(dòng),本文就來(lái)介紹一下QT應(yīng)用啟動(dòng)失敗排查方法小結(jié),具有一定的參考價(jià)值,感興趣的可以了解以下
    2023-09-09

最新評(píng)論