C++が末尾再帰の最適化を行えないわけ

ふと思いついたので、ちょっとした小話。
まずは、末尾再帰版sum。

#include 

int sum(int i, int s) {
  if (i == 0) return s;
  else return sum(i-1, s+i);
}

int main()
{
  std::cout << sum(1000000, 0);
}

gccでもclでもちゃんと実行できる。が、1行入れるだけで破綻する。

int sum(int i, int s) {
  std::string str("");
  if (i == 0) return s;
  else return sum(i-1, s+i);
}

なんでだろう。つまり、stringのデストラクタ呼び出しが控えてるってことだ。呼び出し順を保存するためには、sumの呼び出しの前に破壊するわけにはいかない。strがスコープ抜ける前にデストラクタで一仕事待ってるので、困ったことになる。っていうか、デストラクタで仕事すべきではないんじゃなかったか。この辺、いつ破壊されるかわからないよーん、と開き直ってGCしてれば最適化できるわけだ。ホントかな? たぶん。

class C {
public:
  ~C() {}
};

int sum(int i, int s) {
  C c;
  if (i == 0) return s;
  else return sum(i-1, s+i);
}

意外とこれだけでgccはダメ。デストラクタを書かなかったら大丈夫ではあった。clはまだがんばれる。あ、gcc4なら-O3にすれば通るようだ。
NRVOの件もそうだったけど、なんでもできすぎると最適化がかけづらいよねぇ、っていうはなし。あぁ、最近研究室内でのOCamlの肩身が狭い。