12

私はいくつかのC++静的分析ルールを実装していますが、そのうちの1つは、関数が関数の参照パラメーターへの参照またはポインターを返すことを禁止しています。つまり、以下はすべて非準拠です。

int *f(int& x) { return &x; } // #1
const int *g(const int& x) { return &x; } // #2
int& h(int& x) { return x; } // #3
const int& m(const int& x) { return x; } // #4

これを正当化する理由は、「参照パラメーターが一時オブジェクトであるか、パラメーターへの参照であるかは、実装で定義された動作です」ということです。

ただし、C ++のストリーム演算子はこのように記述されているため、私はこれに戸惑っています。

std::ostream& operator<<(std::ostream& os, const X& x) {
    //...
    return os;
}

C ++のストリーム演算子は、一般に実装定義の動作を示さないと私はかなり確信していると思います。では、何が起こっているのでしょうか。

現在の私の理解によれば、一時的なものは非定数参照にバインドできないことに基づいて、#1と#3が明確に定義されていると思います。したがってint& x、スコープを超える存続期間を持つ実際のオブジェクトを指します。したがって、そのオブジェクトへのポインタまたは参照を返すことは問題ありません。一時的なものがバインドされている可能性があるため、#2は危険であると予想しconst int& xます。その場合、そのアドレスを取得しようとするのは悪い計画のように思われます。#4についてはよくわかりません-私の腸の感覚は、それも潜在的に危険であるということですが、私にはわかりません。特に、次の場合に何が起こるかはわかりません。

const int& m(const int& x) { return x; }
//...
const int& r = m(23);
4

2 に答える 2

8

あなたが言うように、#1と#3は問題ありません(ただし、#1は間違いなく悪いスタイルです)。

#4は#2と同じ理由で危険です。これにより、const 参照をその存続期間を過ぎた一時オブジェクトに伝搬できます。

確認しよう:

#include <iostream>

struct C {
  C() { std::cout << "C()\n"; }
  ~C() { std::cout << "~C()\n"; }
  C(const C &) { std::cout << "C(const C &)\n"; }
};

const C &foo(const C &c) { return c; }

int main() { 
   const C &c = foo(C());
   std::cout << "c in scope\n";
}

これは以下を出力します:

C()
~C()
c in scope
于 2012-07-18T09:43:02.423 に答える
1

C++11 では、右辺値参照のオーバーロードもある場合、#2 と #4 を安全にすることができます。したがって:

const int *get( const int &x ) { return &x; }
const int *get( const int &&x ) { return nullptr; }

void test() {
    const int x = 0;
    const int *p1 = get( x ); // OK; p1 is &x.
    const int *p2 = get( x+42 ); // OK; p2 is nullptr.
}

したがって、それらは危険ですが、プログラマーが何をしているのかを知っていれば、安全に使用できます。これを禁止するのは大変なことです。

(おそらく、const rvalue 参照のオーバーロードが非公開にされたり、未定義のままになったり、コンパイル時またはリンク時のエラーが発生した場合の方が安全です。これは、参照を返すが何もない #4 の場合に特に当てはまります。への参照を返すのが適切であり、言語は null への参照を許可していません。)

于 2012-07-23T13:35:15.823 に答える