2017-03-07 75 views
12

我有一個std::function指向一個函數。在這個函數裏,我將指針改爲另一個函數。在被調用的函數中更改函數指針(std :: function)是否安全?

std::function<void()> fun; 

void foo() { 
    std::cout << "foo\n"; 
} 

void bar() { 
    std::cout << "bar\n"; 
    fun = foo; 
} 

int main() { 
    fun = bar; 
    fun(); 
    fun(); 
} 

我看不出有什麼問題,它只是罰款(見here),但我不知道這是否是合法的,這樣做的。有沒有什麼我不想這樣做(也許在C++標準草案(我很快檢查,但迄今沒有看到任何東西))?

+6

這沒什麼問題。而已。 –

+1

由於難以控制全局變量的狀態(你應該儘量避免),這是合法但不好的風格。 – Aziuth

+0

我有一個迷你遊戲項目,我使用'std :: function'作爲主循環回調(稱爲60次/秒),並將其分配給不同的方法來改變遊戲狀態(菜單選擇,播放,暫停等)。它運行良好。 – tntxtnt

回答

10

這與函數指針是合法的。

當您使用目標分配或構建std::function時,它會創建目標的副本。在將函數分配給std::function的情況下,這實際上將函數指針存儲爲目標對象。

當您調用operator()時,需要返回如果您使用參數調用目標會發生的情況。

std::function中作爲副本存儲的函數對象副本的「主體」中,如果重新指派給std::function,則會破壞舊的目標函數對象。

銷燬函數指針對指向的函數中執行的代碼的有效性沒有影響。

但是,如果你有存儲功能對象(lambda表達式,手動的,其他std::function S,std::bind等),在分配點你會碰上一個類時運行的方法的一般規則this被銷燬。簡而言之,您將無法再依靠您的實例的「本地狀態」進行任何操作。

std::function<void()> fun; 
struct bob { 
    std::string name; 
    bob* next = 0; 
    void operator()() const { 
    std::cout << name << "\n"; 
    if (next) fun = *next; 
    // undefined behavior: 
    // std::cout << name << "\n"; 
    } 
}; 
bob foo = {"foo"}; 
bob bar = {"bar", &foo}; 

int main() { 
    fun = bar; 
    fun(); 
    fun(); 
} 

live example

正如你所看到的,這可能是脆弱的。

-1

它可能會回來咬你,如果你沒有適當的考慮和代碼文件,但沒有合理的理由,它不會工作。

在C++中,函數的地址是不需要的,或者在返回編碼的函數中。

如果它在某些語言中不起作用,編譯器可能不會接受它 - 如果它是一個體面的編譯器。

+2

不同意一般的最後一句話。在另一種情況下,編譯器能夠像程序員想要的那樣處理未定義的行爲,但仍未定義。 – Aziuth

+0

一半體面的編譯器不會接受某些行爲可能未定義的情況。在幾年前,c編譯器會接受最可怕的代碼。幸運的是,大多數C++編譯器都非常嚴格。 – Quandon

+0

一個體面的編譯器會讓你編譯'* nullptr' ... – YSC

相關問題