2013-09-16 61 views
2

考慮下面的(有點構思)例如:標記的功能具有無副作用用Visual C++

// a.cpp 
int mystrlen(const char* a) { 
    int l = 0; 
    while (a[l]) ++l; 
    return l; 
} 

// b.cpp 
extern int mystrlen(const char*); 
int foo(const char* text) { 
    return mystrlen(text) + mystrlen(text); 
} 

這將是非常好的,能告訴編譯器mystrlen()沒有副作用,因此它可以重複使用mystrlen(text)的舊結果,而不是調用它兩次。

我沒有在文檔中找到任何關於它的文章,或者restrict或其中一個差異似乎也沒有做到這一點。查看所有優化的輸出代碼(開關/Ox),表明編譯器確實生成了兩個調用。它甚至會這樣做,如果我把兩個功能放在一個模塊中。

任何解決方案,或任何人都可以確認在VC++中沒有解決方案?

+0

你想要一個功能更強大的語言。 – SLaks

+0

即使打開所有優化,它是否會這樣做(稱爲兩次)?如果它在同一個源文件中呢?還是一樣的結果? – Floris

+0

@弗洛里斯:我使用過'/ Ox',即使在一個模塊中它會將函數內聯兩次。 – cxxl

回答

-1

因爲C++是一種命令式語言而不是功能語言,所以你試圖實現的是不可能的。

看起來你在這裏期望的行爲就是參照透明性,它沒有辦法在C++中告訴編譯器(但是在像Haskell這樣的純函數式編程語言中是隱含的) 。

希望未來的C++標準將引入一個關鍵字,使我們可以將函數標記爲「純」或「無副作用」。

+2

我不明白爲什麼勢在必行與功能有什麼關係能夠標記一個某些功能沒有副作用(即對其他物體造成影響)。毫無疑問,它可以用C++來實現。問題是,是嗎? – cxxl

0

你在找什麼不會幫你。

一般來說,即使相信函數沒有副作用,編譯器也不能忽略這些調用。你從哪裏得到那個指針?信號處理程序是否可以訪問同一個指針?也許另一個線程?編譯器如何知道指針指向的內存不會從其下面改變出來?

編譯器經常消除函數體內的冗餘讀取,即使是通過指針獲取的東西。但是他們可以做甚至應該做的事情是有限的。

這裏你要求編譯器相信一個空的指針,你必須知道誰會知道在哪裏將保持兩個函數調用之間的一致內容。這是很多假設。當然,你還沒有宣佈你的指針是不穩定的,但仍然有很多假設。

現在,如果你在棧上有一個緩衝區,並且連續兩次將它傳遞給那個函數,編譯器可以很安全地假設,如果你沒有將指針傳遞到其他地方,那個緩衝區的內容在某些意想不到的時間,程序中的某些隨機的其他東西不會被改變。

例如:

// b.cpp 
extern int mystrlen(const char*); 
int foo(int bar) { 
    char number[20]; 
    snsprintf(number, 20, "%d", bar); 
    return mystrlen(number) + mystrlen(number); 
} 

鑑於假設的編譯器可以對什麼snprintfnumber沒有考慮到這是一個庫函數,它可能然後的Elid到mystrlen第二個電話,如果有申報方式mystrlen沒有副作用。