2011-09-12 32 views
24

使用,結果可能會接收比綁定對象所期望的更多參數。從概念上講:是否使用boost :: bind傳遞比預期更安全的參數?

int func() { return 42; } 
boost::function<int (int,int,int)> boundFunc = boost::bind(&func); 
int answer = boundFunc(1,2,3); 

在這種情況下,接收func() 1,2和3在堆棧上,即使它的簽名表明它不接受任何參數。

這不同於更典型的使用boost::bindpartial application,其中數值是固定的,產生一個boost::function即需要更少的參數,但調用綁定對象時提供的參數正確數目的某些對象。

以下代碼適用於MSVC++ 2010 SP1。這是發佈的簡化形式;最初的代碼也可以在Linux下運行在g ++ 4.4下。

下面是根據C++標準定義好的嗎?

#include <iostream> 
#include <boost/bind.hpp> 
#include <boost/function.hpp> 

using namespace std; 

void func1(int x) { std::cout << "func1(" << x << ")\n"; } // end func1() 

void func0() { std::cout << "func0()\n"; } // end func0() 

int main(int argc,char* argv[]) 
{ 
     typedef boost::function<void (int)> OneArgFunc; 
     OneArgFunc oneArg = boost::bind(&func1,_1); 
     // here we bind a function that accepts no arguments 
     OneArgFunc zeroArg = boost::bind(&func0); 
     oneArg(42); 
     // here we invoke a function that takes no arguments 
     // with an argument. 
     zeroArg(42); 

    return 0; 
} // end main() 

我明白爲什麼zeroArg(42)作品:未使用的參數是通過調用程序放在堆棧上根本就沒有訪問過由所謂的程序。被調用例程返回時,調用例程清理堆棧。由於它將參數放在堆棧上,它知道如何刪除它們。

將移動到另一個架構或編譯器打破這個?更積極的優化會打破這個嗎?


我正在尋找更強大的聲明,無論是從Boost文檔還是從標準文檔。我還沒有找到明確的立場。

使用調試器並查看程序集和堆棧,很明顯第一個示例中的func未接收到值1,2和3:您在前面是正確的。 func0在第二個例子中也是如此。至少對於我所看到的實現,MSVC++ 2010SP1和g ++ 4.4/Linux來說至少如此。

望着引用Boost文檔,它不是明確的,因爲我想它是安全的,通過額外的參數:

bind(f, _2, _1)(x, y);     // f(y, x) 

bind(g, _1, 9, _1)(x);     // g(x, 9, x) 

bind(g, _3, _3, _3)(x, y, z);   // g(z, z, z) 

bind(g, _1, _1, _1)(x, y, z);   // g(x, x, x) 

需要注意的是,在上例中,所產生的函數對象bind(g, _1, _1, _1)不包含對第一個以外的任何參數的引用,但它仍可以與多個參數一起使用。 任何額外的參數都將被忽略,就像在第三個示例中忽略第一個和第二個參數一樣。 [重點煤礦]

聲明關於額外的參數被忽略是不是明確的,因爲我想說服我,這是在一般情況下正確的。查看TR1,從3.6.3節可以明顯看出,可以調用與bind返回的可調用對象的參數數目不同,但是目標對象預期的參數數目不同。這是最好的保證嗎?

+5

+1爲完美的第一個問題。我愛你一點點。 –

回答

14

是的,這是安全和便攜的–,如the documentation中明確提到的那樣,由boost::bind返回的綁定表達式會默默地忽略額外的參數。

即,在第一示例中,func確實接收值123boundFunc接收值12,和3並將它們轉發到所包含的結合表達,這可以安全地接收和忽略它們,然後調用func()。同樣,在第二個示例中,zeroArg收到值42,並將其轉發給包含的bind-expression,它接收並忽略該值,然後調用func0()

+3

確實。 'func()'不會在調用堆棧上神奇地接收到比它期望的更多的對象; 'boost :: bind'(一箇中間函數,真的)接受它們(並且它很好),然後根本不會將它們傳遞給最終的被調用者。 –

+0

使用調試器並查看程序集和堆棧,很明顯,第一個示例中的「func」沒有接收到值1,2和3:您在前面是正確的。至少對於我所看到的實現,MSVC++ 2010SP1和g ++ 4.4/Linux。 –

相關問題