Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

Frequently Asked Questions(常見問題)

1. Why can't I compare boost::function objects with operator== or operator!=?為什麼我不能用 operator== 或 operator!= 比較 boost::function 對像?)
2. I see void pointers; is this [mess] type safe?(我看到了 void 指針,這會[擾亂]類型安全嗎?)
3. Why are there workarounds for void returns? C++ allows them!(為什麼會有專門應付空返回的 workarounds,C++ 是允許它們的!)
4. Why (function) cloning?((函數)為什麼要克隆?)
5. How much overhead does a call through boost::function incur?(通過 boost::function 進行調用會導致多少代價?)
1.

Why can't I compare boost::function objects with operator== or operator!=?(為什麼我不能用 operator==operator!= 比較 boost::function 對像?)

boost::function 對像之間的比較不能「較好地」實現,因此不再實現。對於 f == g 的典型的語義要求是給定 boost::function 對像 fg

  • 如果 fg 存儲相同類型的函數對象,使用那個類型的 operator== 去比較它們。
  • 如果 fg 存儲不同的函數對象,返回 false

fg 存儲的函數對象都沒有 operator== 時就會發生問題:我們想讓表達式 f == g 無法編譯,這就像在標準容器中發生的事情。然而,對於 boost::function 來說這是無法實現的,因為它被賦予一個函數對像後,它不可避免地「抹去」一些類型信息,所以其後它就不能再試圖去調用 operator==:它必須既要在現在找到一種調用 operator== 的方法,又要在其後永遠不能調用它。注意,舉例來說,如果你試圖將一個 float 值放入一個 boost::function 對像時會發生什麼:你將得到一個來自於賦值操作符或構造函數,而不是 operator() 的錯誤,因為函數調用表達式肯定會進入構造函數或賦值操作符。

最有希望的方法是找到一種檢測 operator== 是否能被特定類型調用的方法,並僅僅在它可用的時候才支持它;在其它情況下,拋出一個異常。然而,到目前位置,還不知道有什麼方法可以檢測一個任意的操作符表達式 f == g 是否被合適地定義。已知最好的解決方案有以下這些令人不快的性質:

  1. 對於 operator== 不可訪問的對象(例如,因為它是 private 的),會在編譯時失敗。
  2. 如果調用 operator== 是有歧義的,會在編譯時失敗。
  3. 如果 operator== 的聲明是正確的,即使 operator== 可能沒有被編譯,看上去就是正確的。

所有這些問題都被轉化為 boost::function 的構造函數或賦值操作符中的失敗,即使,用戶從來沒有調用過 operator==。我們不能對用戶做這樣的事。

另一種選擇方案是把負擔放到要使用 operator== 的用戶身上,例如,通過提供一個他們可以特化的 is_equality_comparable traits。這是一個可用的方案,但實際上是很危險的,因為忘記特化這個 traits 會導致由 boost::functionoperator== 拋出的意想不到的異常。這在本質上否定了 operator== 在它最期望的上下文(多目標回調)中的可用性。Signals 庫有一個和它差不多的方法。

2.

I see void pointers; is this [mess] type safe?(我看到了 void 指針,這會[擾亂]類型安全嗎?)

是的,即使 boost::function 使用了 void 指針和指向返回 void 也沒持有參數的函數的指針,它也是類型安全的。實際上,所有類型信息都編碼在管理和調用函數指針和函數對象的函數中。只有這些函數才能被嚴格的「被 void 指針指向的類型」或「指向 void 函數的指針類型」實例化。這兩者的前提是需要在 void 指針和對像指針之間或在不同類型的函數指針之間可以安全地轉型(倘若你沒有使用錯誤的類型調用一個函數指針)。

3.

Why are there workarounds for void returns? C++ allows them!(為什麼會有專門應付空返回的 workarounds,C++ 是允許它們的!)

空返回被 C++ 標準允許,就像下面這樣的代碼片段:

void f();
void g() { return f(); }

這是 boost::function 的一個合法使用,因為空返回沒有被使用。利用空返回,我們可以企圖編譯如下病態的代碼:

int f();
void g() { return f(); }

實際上,沒有使用的空返回允許 boost::function 吞下一個返回值。這是為了和用戶在使用不嚴格匹配的參數賦值和調用函數與函數對像時保持一致。

4.

Why (function) cloning?((函數)為什麼要克隆?)

在 2000 年 11 和 12 月,克隆和引用計數的問題爭論了很長時間,最終決定克隆提供了更加可預言的語義。我不想對這場爭論舊調重彈,但是如果對於一個特定應用來說克隆是不正確的,reference-counting allocator(引用計數分配器)也可以使用。

5.

How much overhead does a call through boost::function incur?(通過 boost::function 進行調用會導致多少代價?)

boost::function 的成本可以被相當一致地測量,在現代的 >2GHz 的平台上與直接的內聯代碼相比大約相差 20ns +/- 10 ns。

然而,你的應用的性能可能會得益於或受損於 boost::function,依賴於你的 C++ 優化器的優化。與一個標準函數指針相比,大約 10% 的差距,相對於使用 boost::function 調用一個包含依賴於你的編碼環境的密集循環的函數來說,是無足輕重的。

[Answer provided by Matt Hurd. See http://article.gmane.org/gmane.comp.lib.boost.devel/33278]

Last revised: November 03, 2006 at 19:41:09 GMT

Copyright 2001-2004 Douglas Gregor

PrevUpHomeNext