7

次のコードがどのようにコンパイルされるか、またはコンパイルされないかがわかりません:

struct Temp
{
  int i;
};

int main(int argc, char * argv[])
{
   //Temp &ref1 = (Temp){42}; // Error, as expected
   Temp &ref2 = *(Temp*)&(Temp){42}; // A-OK
   std::cerr << ref2.i << std::endl;
   return 0;
}

g++ 4.4.4 を使用しています。

4

3 に答える 3

2

あなたのコードは実際にはC++ではありません。これは、C99機能である複合リテラルを使用します。C99では、左辺値に評価され、リテラルのアドレスを取得することは完全に問題ありません。この拡張機能をC++に統合すると、GCCはそのルールを変更して右辺値にし、右辺値も生成する通常のキャストのC++の既存のルールにそれらの分類をより適切に適合させるように見えます。

&(Temp){42}GCCは、私が一時的なアドレスを取ると不平を言って、好きではありません。これは、まだ受け入れているが実際には気に入らない無効なコードに関する警告です。同じ警告が、のような他の明らかに間違ったコードにも与えられます&A()。これは、正当な関数スタイルのC ++キャストであり、右辺値も生成するため、address-of演算子のオペランドとして使用できません。

次のテストでわかるように、GCCによる複合リテラルのC ++への統合も、一時的なものを時期尚早に破壊します。

#include <iostream>
struct B {
  ~B() {
    std::cout << "~B" << std::endl;
  }
};
struct A { int i; B b; };

int main() {
  A *a = &(A){0};
  std::cout << "main" << std::endl;
}

C99では、リテラルが参照するオブジェクトは、ブロック全体で存続します(自動保存期間があります)。GNU C ++では、オブジェクトは、そのブロックの終わりに達する前に、完全な式の終わりですでに破棄されています( "〜B"は "main"の前に出力されます)。

于 2011-02-21T01:07:49.013 に答える
0

私はこれについて誤解される可能性がありますが、これはコンパイラのバグのようです。C ++ ISO規格、§5.3.1 / 2では、&演算子について次のように説明しています。

単項&演算子の結果は、そのオペランドへのポインターです。オペランドは左辺値または修飾IDでなければなりません。

セクション§5.4/1では、キャスティング演算子について次のように説明しています。

式(T)の結果-式は型Tです。Tが参照型の場合、結果は左辺値になります。それ以外の場合、結果は右辺値になります。

これは次のことを示唆しているようです

(Temp){42}

右辺値を生成します。これは、を使用するアドレスを取得することを法的に許可されるべきではありません&

私は以前に仕様を読むのを間違えることが知られていたので、誰かがこれを確認できればそれは素晴らしいでしょう。

于 2011-02-21T00:52:58.807 に答える
0

templatetypedefが言ったように、それはコンパイラのバグのようです。4.6.0バージョンのGCCでコンパイルすると、次のようになります。

error: taking address of temporary [-fpermissive]

そしてもちろん、-fpermissiveを追加すると、コンパイルはされますが文句を言いますが、それでもクラッシュせず、正しい結果を出力します。GCCは「寛容な」条件下で少し浮気していると思います。

于 2011-02-21T01:10:05.660 に答える