2016-06-15 39 views
0

我認爲這是一個最佳實踐問題。C++通過已通過的參考來修改自我

在C++中,我有一個類似Python的os.path的文件系統路徑的包裝類。在這個包裝類中,有一個名爲「Split」的成員函數,用於搜索最後發生的路徑分隔符,並將其分解爲「尾部」(路徑的最後部分)和「頭部」(其他所有內容)。就目前而言,該函數使用自己的成員變量m_filepath進行分割。

一些代碼:

class FilePath { 
    public: 
     void Split(FilePath& head, FilePath& tail) const 
     { 
      FilePath h; 
      FilePath t; 
      //initialize h, t with portions of m_filepath... 
      head = h; 
      tail = t; 
     } 
    private: 
     std::string m_filepath; 
}; 

int main(int argc, char ** argv) 
{ 
    FilePath some_path_1("/"); 
    FilePath some_path_2("/home/"); 
    some_path_1.Split(some_path_1, some_path_2); 
    return 0; 
} 

當我做這樣的事情,some_path_1的m_filepath將由什麼「頭」覆蓋原來是。常量運算符似乎也不介意。

我的問題是,處理這個問題的最佳方法是什麼?拋出異常?允許覆蓋該對象(這令我擔心,聽起來不安全),並告訴開發人員謹慎?聰明地使用return語句?

+1

我不認爲你需要做任何事情;如果有人寫'some_path_1.Split(some_path_1,some_path_2);'那麼你可以假設他們知道他們覆蓋'some_path_1'的舊內容。在路徑操作中,做這種事情並不少見 - 在原地提取路徑的一部分,不必再創建另一個變量。 –

+0

只需返回一對新路徑。它沒有什麼特別的巧妙。拋棄輸出參數。函數返回結果。 –

回答

0

編輯啊!我剛剛意識到你想要做什麼Split():將this分爲headtail - 並希望他們不會將this轉換爲headtail

在另一種情況下,operator =(Class &rhs)的最佳做法是首先將&rhsthis進行比較,以避免確切的問題 - 但我認爲無論如何您都不知道這個問題。在你提供的用法中,不僅清楚將要發生什麼,你的實現足以讓它發生。我不會擔心(就像@ M.M說的)。


當你有一個成員函數,期望的是,該函數將在類的實例進行操作:即,Split()自行關閉,或放棄有關其自身的一些信息。

你想要的是一個static成員函數:一個函數,當它和它的類關聯時,它不會在假設的this上運行。使Split()功能static

static void Split(...); // Note no concept of const required - no `this` to modify! 

,並調用它像這樣:

FilePath::Split(some_path_1, some_path_2); 

或者,你可以讓這個Split()回報尾部,並修改自己只是頭部:

FilePath Split(); 

但是在那種情況下,在哪個方向上有點模糊分裂正在發生。如何:

FilePath SplitHead(); 

FilePath SplitTail(); 

最後兩可在static方法方面實現以上,像這樣:

FilePath FilePath::SplitHead() { 
    FilePath head = *this; 
    Split(head, *this); 
    return head; 
} // FilePath::SplitHead() 

FilePath FilePath::SplitTail() { 
    FilePath tail; 
    Split(*this, tail); 
    return tail; 
} // FilePath::SplitTail() 
+0

關於你的第一個答案,我目前不保存成員變量m_filepath static,它對於FilePath實例是唯一的,並且使用構造函數發送的任何內容進行初始化。 Split使用m_filepath進行分割,並將結果存儲在頭部和尾部。不會使靜態成員函數需要對該設計進行更改? 如果我對最初的問題含糊不清,我已經更新以防萬一。 – FlamboyantBacon

+0

我沒有建議你讓'm_filepath'靜態 - 我明白它應該是'FilePath'的每個實例成員。我建議做'Split()'函數'static'。正如我所描述的那樣,這意味着函數本身並不與任何特定的實例綁定 - 但仍然與「FilePath」操作相關聯(並且可以訪問其「私有」成員) –

+0

我將該問題解釋爲「 this-> m_filepath'用於'Split'函數,所以它必須是一個成員 –

1

的大問題,編寫代碼這種方式是清潔代碼的誘惑向上,以便分裂看起來是這樣的:

void Split(FilePath & h, FilePath & t) { 
    h.m_filepath = getHead(m_filepath); 
    t.m_filepath = getTail(m_filepath); 
} 

但由於h.m_filepath = ...實際上正在改變this.m_filepath第二個呼叫沒有做什麼預期。 (請注意,你的代碼目前很好 - 但很脆弱)。

(潛在)問題的根源是使用引用作爲返回值並需要多個返回值的組合。但是C++ 11通過tie支持多個返回值。

所以我想實現這個作爲

class FilePath { 
    public: 
     std::pair<FilePath,FilePath> Split() const 
     { 
      FilePath h; 
      FilePath t; 
      //initialize h, t with portions of m_filepath... 
      head = h; 
      tail = t; 
      return std::make_pair(h,t); 
     } 
    private: 
     std::string m_filepath; 
}; 

然後使用是這樣的:

int main(int argc, char ** argv) 
{ 
    FilePath some_path_1("/"); 
    FilePath some_path_2("/home/"); 
    std::tie(some_path_1, some_path_2) = some_path_1.Split(); 
    return 0; 
} 

而且它很清楚,some_path_1some_path_2會得到他們的值更新,而你不知道不必擔心寫入參數會改變這一點,因爲沒有任何爭論了。

+0

這可能是我正在尋找的答案。我不知道C++ 11允許多個返回值。 C++ 11是我一直在使用的(雖然這是一個個人項目,所以我願意更新到14,一旦我對它有所瞭解)。 – FlamboyantBacon