實(shí)現(xiàn)一個(gè)不拋異常的swap函數(shù)

template<typename T>
void swap(T& a, T& b)
{
    T temp(a);  // 拷貝構(gòu)造
    a = b;      // 拷貝賦值運(yùn)算符
    b = temp;   // 拷貝賦值運(yùn)算符
}

一個(gè)基本的swap函數(shù)大概如上所述,但是對(duì)某些類型而言。典型比如:pimpl手法(pointer to implementation),這些復(fù)制沒有必要。

class WidgetImpl
{
    public:
        ...
    private:
        int a, b, c;
        std::vector<double> v;    // 意味著拷貝開銷很大
};

class Widget
{
    public:
        Widget(const Widget& rhs);
        Widget& operator=(const Widget& rhs)
        {
            ...
            *pImpl = *(rhs.pImpl);
        }
    private:
        WidgetImpl* pImpl;
}

一旦需要置換兩個(gè)Widget對(duì)象值,我們只需要交換pImpl指針,但缺省的swap算法不知道這一點(diǎn),它不止拷貝三個(gè)Widget,還拷貝三個(gè)WidgetImpl對(duì)象。

我們希望能夠告訴std::swap,當(dāng)Widgets被置換時(shí)真正該做的是置換其內(nèi)部的pImpl指針,確切的做法就是:將std::swap針對(duì)Widget特化。

namespace std {
    template<>
    void swap<Widget>(Widget& a, Widget& b)
    {
        swap(a.pImpl, b.pImpl);
    }
}

通常我們不被允許改變std命名空間內(nèi)的任何東西,但可以為標(biāo)準(zhǔn)的template制造特化版本。
雖然上面的代碼看起來(lái)達(dá)到我們的目的,但實(shí)際上這個(gè)函數(shù)無(wú)法通過編譯,因?yàn)樗髨D訪問 a 和 b 內(nèi)的Impl指針,而那是private的。
但我們可以在內(nèi)部實(shí)現(xiàn)一個(gè)swappublic成員函數(shù)做真正的置換工作,然后將std::swap特化,令它調(diào)用成員函數(shù):

class Widget
{
    public:
        ...
        void swap(Widget& other)
        {
            using std::swap;
            swap(pImpl, other.pImpl);
        }
    ...
};

namespace std
{
    template<>
    void swap<Widget>(Widget& a, Widget &b)
    {
        a.swap(b);
    }
}

這種做法不僅能通過編譯,還與STL容器有一致性,因?yàn)樗械腟TL容器也都提供有public swap成員函數(shù)和std::swap特化版本。

  • using std::swap

  • 不拋異常
    成員版swap最好實(shí)現(xiàn)成不要拋異常,因?yàn)?code>swap的一個(gè)最好應(yīng)用是幫助class提供異常安全保障。此技術(shù)基于一個(gè)假設(shè):成員版的swap絕不拋異常。但這一約束只約束于成員版,不可施行于非成員版,因?yàn)?code>swap缺省版本是以拷貝構(gòu)造和拷貝賦值操作符為基礎(chǔ),而一般情況下兩者都允許拋異常。

總結(jié)
  • 如果swap的缺省實(shí)現(xiàn)對(duì)你的classclass template提供可接受的效率。那么不需要做額外的操作。
    如果swap的缺省實(shí)現(xiàn)版本效率不足,試著做下面的事情:
    • 提供一個(gè)public swap成員函數(shù),讓它高效的置換你的類型的兩個(gè)對(duì)象值,并且這個(gè)swap函數(shù)絕不能拋出異常。
    • 在你的classtemplate所在的命名空間內(nèi)提供一個(gè)non-member swap,并令它調(diào)用上述swap成員函數(shù)。
    • 如果你在編寫一個(gè)class而非class template,為你的class特化std::swap。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容