2012-11-15 3 views
7

次のプログラムは、fun 2(MAXD + 1)回呼び出します。しかし、(私の考えが正しいなら)最大再帰深度は決してMAXDを超えてはなりません。コンパイルに時間がかかるかもしれませんが、RAMを食べるべきではありません。なぜこのconstexprコードはGCCにすべてのRAMを食べさせますか?

#include<iostream> 

const int MAXD = 20; 

constexpr int fun(int x, int depth=0){ 
    return depth == MAXD ? x : fun(fun(x + 1, depth + 1) + 1, depth + 1); 
} 

int main(){ 
    constexpr int i = fun(1); 
    std::cout << i << std::endl; 
} 

問題は、自分のRAMを食べることがまさにそれが何であるかということです。私がMAXDを30に変えると、GCC 4.7.2がすぐに3GB程度を割り当てた後にノートパソコンがスワップを開始します。私はまだそれにアクセスすることができないので、私はclang 3.1でそれを試していません。

これはGCCがテンプレートを使用する場合と同じように、関数呼び出しを賢明にしてメモを取ろうとしているということだけです。これがそうであれば、MRUキャッシュテーブルなどのサイズのように、どのくらいメモをしているのかに限界がないのは奇妙なことではありませんか?私はそれを無効にするスイッチが見つかりませんでした。

どうすればいいですか? 私は遺伝的プログラミングや何かのような高度なコンパイル時ライブラリを作るという考えを抱いています。コンパイラにはコンパイル時のテールコールの最適化がないので、ループには再帰が必要であると心配しています(必要な場合は少し醜いと思われる最大再帰深度パラメータを設定しても)それは無意味なスタックフレームで。したがって、私は深いスタックなしで任意に多くの関数呼び出しを取得するための上記の解決策を考え出しました。そのような機能は、折畳み/ループまたはトランポリングに使用できます。

EDIT: 今、私はclang 3.1で試してみましたが、どれくらい長く動作させても(つまりMAXDをどれくらい高くしても)メモリがまったくリークしません。 CPU使用率はほぼ100%で、メモリ使用率はほぼ0%です。おそらくこれはGCCのバグです。

+0

私が確認しています関数ランタイムを実行し、長時間実行することができますが、RAMをまったく使用しないことを確認することで、スタックはMAXDを超えることはありません。 – Gurgeh

+1

http://gcc.gnu.org/bugs/で推奨されているように報告する必要がありますか? – osgx

+0

@osgxそれは本当にバグではありません。標準によると、彼らは私のRAMに好きなことをすることができると思います。また、私は彼らが何をしているかを知っている人(あなたが誰であるかを知っている;)が理由を教えてくれるようにしたい。 – Gurgeh

答えて

1

あなたの答えはあなたのコメントにあります。「関数ランタイムを実行し、私がそれを長期間実行できる間に観察すること」は、fun(x + 1、depth + 1 )。

constexprを削除してコンパイル時関数ではなくランタイム関数に変更し、それが非常に深く再帰していることを示す長い時間が経過したことがわかったとき。

コンパイラによって関数が実行されると、深く再帰する必要がありますが、実際にはマシンコードを生成して実行していないため、スタックを再帰に使用しません。

+0

もちろんです。それはまあまあです。コードを試しましたか? – Gurgeh

+0

何かが長時間走れる唯一の方法は、深く再考することだけではありません。また、私のコードが行うことである、広く分岐することもできます。 – Gurgeh

+0

コードは広く枝分かれしません。それは1つのブランチしか持たず、再帰を止めるまでブランチの同じ側を各再帰で取ります。 –

2

これは、constexprのに関する決定的な文書ではないかもしれないが、それはgcc constexpr wiki.

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf

からリンク主要ドキュメントです...そして、それは言う...

我々は( still)は定数式ですべての形式で再帰を禁止します。 定数式の評価で の再帰深度の実装制限が から永遠に再帰する可能性があるため、厳密には必要ではありません。しかし、 が再帰のための説得的なユースケースを見るまで、私たちはそれを許可することを提案しません。

だから、

、私はあなたが(それを実行する/多分、関数全体をインラインを生成しようとし、その後の評価)言語の境界とgccがconstexprのを実装することを選択したような方法に直面してぶつけている期待

+0

@Downvoter - 説明するケア? – Roddy

+0

その文書は古すぎると思います。この標準では再帰を禁止していませんが、gccとclangの両方で512回の再帰に関するデフォルトの制限が示唆されていますが、ユーザーが上書きできるようにしています。あなたは問題がmemoizationではないことは間違いないかもしれませんが(gccがconstexprsにそれをしていることは分かっていますが)、コードをインライン展開します。 – Gurgeh

+0

@Gurgeh - はい - 実際の標準を除いて、可能なすべてのドキュメントにWebが散在していることは、ISO標準の一般的な問題です.- "recursionsの数"または再帰の深さに関する推奨制限はありますか?あなたの場合のように、深さは20ですが、「再帰の数」は、あなたが言うように2^MAXD-1と考えることができます... – Roddy

関連する問題