2011-05-27 19 views
5

我正在執行(作訓練用途)冒泡排序函數模板:使用無任務交換有沒有明顯的缺點?

template<typename iterInput, 
     typename predicate> 
void BubbleSort(iterInput first1,iterInput last1,predicate func) 
{ 
    bool swapped(false); 
    do 
    { 
     swapped = false; 
     iterInput begin = first1; 
     iterInput beginMinus = first1; 
     ++begin; 
     for (;begin != last1; begin++,beginMinus++) 
     { 
      if (func(*beginMinus,*begin)) 
      { 
       std::swap(*beginMinus,*begin); 
       swapped = true; 
      } 
     } 
    } 
    while(swapped); 
} 

當我意識到這個功能將不上課,沒有賦值運算符的工作,像這樣的(原諒我的壞名聲):

class NoCopyable 
{ 
public: 
    explicit NoCopyable(int value) : value_(value) {} 
    NoCopyable(const NoCopyable& other) : value_(other.value_) {} 
    ~NoCopyable() {} 
    bool operator<(const NoCopyable& other) { return value_ < other.value_; } 
    void setValue(int value) { value_ = value; } 
    std::ostream& print(std::ostream& os) const { return os << value_; } 
private: 
    NoCopyable& operator=(const NoCopyable& other); 
    int value_; 
}; 

std::ostream& operator<<(std::ostream& os, const NoCopyable& obj) 
{ 
    return obj.print(os); 
} 

struct PrintNoCopyable 
{ 
    void operator()(const NoCopyable& noCopyable) { std::cout << noCopyable << '\n'; } 
}; 

編譯器將引發此錯誤錯誤1個錯誤C2248:「NoCopyable ::運算符=」:不能訪問類中聲明私有成員「NoCopyable」

所以,我稍微修改代碼使用替代的std ::交換功能我的版本交換功能,這裏是代碼:

template<typename T1, 
     typename T2> 
void noAssignmentSwap(T1& t1,T2& t2) 
{ 
    T1 temp(t1); 
    t1.~T1(); 
    new (&t1) T1(t2); 
    t2.~T2(); 
    new (&t2) T2(temp); 
} 

代碼編譯,並給出正確的結果。但是我不完全確定,我記得薩特的文章建議你避免玩物體的生活時間。這篇文章只是通過玩火來警告你,卻沒有給你任何真正的理由。如果T1或T2的拷貝構造函數可以拋出,我可以在異常安全中看到問題。但是,如果允許賦值運算符拋出,則標準版本中存在相同的問題。

在此問題上,你可以看到在這個版本中交換的任何可能的缺點?

乾杯

+0

明確的析構函數調用看起來前途未卜恕我直言 – 2011-05-27 16:30:55

+1

你爲什麼要交換使用兩種不同類型很少用到......?如果他們不同,使用一個對象的位置構造函數與另一個的地址將反正是非常糟糕的... – 6502 2011-05-27 16:30:58

+0

@良好的觀點,它應該只是一個模板參數 – 2011-05-27 16:34:37

回答

6

不同之處在於,當賦值運算符失敗時,仍然有相同數量的對象。

如果您銷燬一個對象並且無法創建新對象,則會丟失一個對象!如果它是容器的一部分,容器的狀態可能也是無效的。

3

這可能會讓代碼的未來維護者感到困惑。

8

二話不說,如果一個類沒有賦值運算符,它的設計者可能沒有打算將它交換。如果他們這樣做了,他們可能也會禁用拷貝構造,所以你的新交換功能仍然無法工作。

至於你的說法,標準庫容器不需要分配 - 這是真的,只要你不想真正做任何與他們有用。這段代碼是爲你編譯的嗎?我想它不會。

+0

+1。好答案。非常精確地陳述! – Nawaz 2011-05-27 16:37:07

+0

@Neil Butterworth如果對象的複製構造函數被禁用,則該對象不能與stl容器一起使用,所以沒有太多的東西需要排序。 – 2011-05-27 16:40:26

+0

@Alessandro所以你正在處理的對象不能分配,但可以複製?根據我的經驗,這種情況非常罕見。你的問題是關於swap()的。 – 2011-05-27 16:43:08

4

你需要一個拷貝構造函數,而不是一個賦值操作符,但兩者是足夠相似,至少在一般情況下,您將有兩個或你有沒有。 IOW,我認爲這通常不會成就很多。

我倒是類是正確的旁邊異或交換技巧:有趣,但一般沒用。