2014-10-28 23 views
3

在C++ Primer 5th,13.2.1類似Act的Like類中,作者創建一個類似於值的類,這意味着每個對象都有自己的類管理的資源副本。一個非常簡單的類,只包含一個指向字符串的指針,而一個int成員函數只是默認的構造函數和複製控制成員。更容易的複製賦值運算符實現?

class HasPtr{ 
    public: 
    HasPtr(const std::string &s = std::string()) :ps(new std::string(s)), i(0){} 
    HasPtr(const HasPtr &p) :ps(new std::string(*p.ps)), i(p.i){} 
    HasPtr &operator=(const HasPtr &rhs); 
    ~HasPtr(){ delete ps; } 
    private: 
     std::string *ps; 
     int i; 
}; 

下面是書

HasPtr &HasPtr::operator=(const HasPtr &rhs){ 
    auto newp = new std::string(*rhs.ps); 
    delete ps; 
    ps = newp; 
    i = *rhs.i; 
    return *this; 
} 

這是很好的考慮到實施操作的=,但我認爲,我們可以使用下面的實現可避免刪除指針和分配新的內存。

HasPtr &HasPtr::operator=(const HasPtr &rhs){ 
    *ps = *rhs.ps; 
    i = rhs.i; 
    return *this; 
} 

我測試我的代碼作品,甚至自我賦值。但是,這個代碼有什麼問題嗎?

+3

在這種情況下工作,因爲'* ps'是可賦值的。情況並非總是如此。 – 2014-10-28 14:08:42

+1

@MikeSeymour我明白了。這是因爲std :: string定義了operator =,所以它起作用。如果成員沒有定義=,那麼我必須使用本書給出的工具。我想到這一點,因爲下一章將比較圖書館交換的性能和該類定義的交換。 – TungWah 2014-10-28 14:16:21

+0

這是什麼意思?爲什麼不把字符串變成非指針成員呢? – 2014-10-28 16:07:24

回答

3

不,你的代碼沒有問題。

*ps 

本身就是一個值類型,所以你可以直接賦值。如果您正在進行更改以改進代碼,則可能需要進一步將ps更改爲std :: string而不是std :: string *。然後,您可以消除對HasPtr類的新增和刪除需求。

如果

*ps 

是不是原始內存指針該類HasPtr管理,你會寫代碼,如從書中的例子。

+0

我只是想避免新的/刪除,所以我不想寫作爲例子。 – TungWah 2014-10-28 15:20:48

0

在您的原始示例中,您已將* ps的內容複製到自身,這是正確的。然而,正如你對此的評論所暗示的那樣,情況並非總是如此。

至於其他的解決方案,這裏是一個(也許這樣的事情會在你隨後的書解釋):

#include <algorithm> 
//... 
HasPtr &HasPtr::operator=(const HasPtr &rhs) 
{ 
    HasPtr temp(rhs); 
    std::swap(ps, temp.ps); 
    std::swap(i, temp.i); 
    return *this; 
} 

這是copy/swap成語。臨時文件從rhs創建,臨時內部與this的成員互換。臨時的死亡,最後,與this的前值。

請注意,沒有明確的內存分配,因爲您依賴複製構造函數來初始創建臨時副本。這意味着這種技術需要一個工作拷貝構造函數和一個工作析構函數。一旦你有了這些,一個賦值操作符就非常簡單,如果這樣做,因爲沒有真正的「grunt work」編碼 - 複製構造函數會處理它。

所以這比書的版本更容易嗎?取決於你如何看待它 - 複製/交換幾乎可以用於任何情況,基本上只需要開始執行「3規則」中描述的三個函數中的兩個函數的工作實現,即複製構造函數和析構函數。賦值運算符通過利用其他兩個函數來進行乘法運算,並執行簡單的交換。

+0

謝謝你的回答。但是首先編譯器生成的賦值操作符只會複製指針,而不是指針指向的內容。其次,我的代碼不會導致內存泄漏,因爲h2擁有的指針總是指向相同的內存,我只是改變內存的內容。 – TungWah 2014-10-28 15:17:31

+0

@TungWah我編輯了我的帖子。是的,你是對的,但正如其他評論所建議的,你逃避了它,因爲對象被指向了內建的複製語義。 – PaulMcKenzie 2014-10-28 15:52:38