2012-06-23 47 views
1

我想在我的構造函數中拋出異常,這樣我就不必處理殭屍對象。不過,我也希望提供一種驗證方法,以便人們可以避免在沒有理由的情況下「處理例外情況」。在GUI中,它不是例外以期望無效數據。不過,我也想避免代碼重複和開銷。 GCC/Microsoft Visual C++編譯器是否足夠聰明,可以消除驗證輸入兩次的低效率,如果沒有,是否有可能取悅的微妙變化?C++:如果所有數據可能已經有效,那麼在構造函數中驗證是否有開銷?

一個例子代碼塊說明我的觀點是如下:

#include <string> 
#include <exception> 
#include <iostream> 

using std::string; 
using std::cout; 
using std::endl; 
using std::exception; 


// a validation function 
bool InputIsValid(const string& input) { 
    return (input == "hello"); 
} 

// a class that uses the validation code in a constructor 
class MyObject { 
    public: 

    MyObject(string input) { 
     if (!InputIsValid(input)) //since all instances of input 
      throw exception();  //has already been validated 
            //does this code incur an overhead 
            //or get optimised out? 

     cout << input << endl;  
    }; 

}; 

int main() { 

    const string valid = "hello"; 

    if (InputIsValid(valid)) { 
     MyObject obj_one(valid); 
     MyObject obj_two(valid); 
    } 

    return 0; 
} 

我預計,這可能不是可能,如果是單獨生成的對象的類文件作爲對象文件沒有辦法,以確保人們將驗證在調用構造函數之前,但是當一個應用程序被編譯並且在一個應用程序中鏈接在一起時,請問可以嗎?

+1

你的編譯器可以吐出彙編代碼,你可以看看它是否被優化了。 – 2012-06-23 18:24:25

+0

相反,用try-catch塊替換'main()'中的if語句可能更好。 – 2012-06-23 18:24:44

+0

考慮到你複製了一個用於初始化MyObject的字符串,我非常懷疑重複檢查的開銷會讓你擔心。除非你的字符串實現_SSO_並且你只使用幾個字符的字符串。 –

回答

5

如果所有數據可能已經有效,那麼在構造函數中驗證是否存在開銷?

是,如果該數據已經驗證,那麼你會招致再次驗證它

的成本是gcc /微軟的Visual C++編譯器足夠聰明,刪除驗證輸入兩次的這種低效率和如果沒有,是否有一個可以取悅的微妙變化?

您可以將輸入封裝在一個對象中,該對象會記住驗證的結果。

template <typename INPUT_TYPE> 
class InputObject { 
    INPUT_TYPE input_; 
    bool valid_; 
public: 
    typedef <typename VALIDATE> 
    InputObject (INPUT_TYPE in, VALIDATE v) : input(in), valid_(v(in)) {} 
    const INPUT_TYPE & input() const { return input_; } 
    bool isValid() const { return valid_; } 
}; 

typedef InputObject<std::string> MyInput; 

class MyObject { 
public: 
    MyObject (const MyInput &input) { 
     if (!input.isValid()) throw exception(); 
     //... 
    } 
}; 

構造函數調用InputObject驗證功能對你來說,並存儲在一個標誌驗證的結果。然後MyObject只是檢查標誌,而不必再次進行驗證。

int main() { 
    MyInput input("hello", InputIsValid); 

    try { 
     MyObject obj_one(input); 
     MyObject obj_two(input); 
    } 
    catch (...) { 
     //... 
    } 
} 

如所建議的通過DeadMG,更強的類型檢查可以通過堅持MyObject只接受驗證的輸入來實現。然後,在構造函數中根本不需要throw。這樣的方案可以通過使NonValidatedInputValidatedInput兩種不同的類型來完成。

template <typename> class NonValidatedInput; 

template <typename T> 
class ValidatedInput { 
    friend class NonValidatedInput<T>; 
    T input; 
    ValidatedInput (const T &in) : input(in) {} 
public: 
    operator const T &() const { return input; }; 
}; 

template <typename T> 
class NonValidatedInput { 
    T input; 
public: 
    operator ValidatedInput<T>() const { return ValidatedInput<T>(input); } 
    template <typename V> 
    NonValidatedInput (const T &in, V v) : input(in) { 
     if (v(input) == false) throw exception(); 
    } 
}; 

NonValidatedInput接受非驗證的輸入,並且執行所述驗證,並且如果驗證成功,可以轉換爲ValidatedInput對象。如果驗證失敗,NonValidatedInput將引發異常。因此,MyObject根本不需要檢查驗證,因爲它的構造函數只接受ValidatedInput

typedef ValidatedInput<std::string> MyInput; 

class MyObject { 
public: 
    MyObject (MyInput input) { 
     std::string v = input; 
     std::cout << v << std::endl; 
    } 
}; 

int main() { 
    try { 
     MyInput input = NonValidatedInput<std::string>("hello", InputIsValid); 
     MyObject obj_one(input); 
     MyObject obj_two(input); 
    } 
    catch (...) { 
     //... 
    } 
} 

這裏的類型安全是相當強的,因爲只有NonValidatedInput可以創建一個ValidatedInput,且僅當驗證成功。

+0

不,使用強類型驗證輸入。 – Puppy

+0

@DeadMG:感謝您的輸入。答案已更新。如果它仍然不能滿足您對強打字的擔心,您是否可以澄清我如何使類型安全性更強?問候 – jxh

+0

它應該看起來像[這](http://pastebin.com/V58d​​9iGG)。請注意,驗證和未驗證的輸入是*兩個完全不同的類型*,並且所有'std :: string'的有效性 - 假設您的輸入函數返回一個未驗證的對象 - * * * * *。 – Puppy

0

優化程序可能會內聯函數InputIsValid(),但大概就這樣。您還需要將您的構造函數記錄爲拋出,並拋出異常類型。就調用該函數的性能成本而言,它可以忽略不計,這是strcmp()的成本。儘管如此,除非該構造函數被用於非常緊密的循環中,否則成本應該可以忽略不計。

相關問題