380

これは少し主観的だと思います。意見が満場一致になるかどうかはわかりません (参照が返される多くのコード スニペットを見てきました)。

私が今尋ねたこの質問に対するコメントによると、参照の初期化に関して、参照を返すことは悪になる可能性があります.[私が理解しているように]削除を見逃しやすくなり、メモリリークにつながる可能性があるためです。

私は例に従って(想像していない限り)、かなりの数の場所でこれを行ったので、これは私を心配しています...誤解しましたか?それは悪ですか?もしそうなら、どれほど邪悪ですか?

ポインターと参照が入り混じったバッグと、C++ を初めて使用するという事実、およびいつ何を使用するかについて完全に混乱しているため、私のアプリケーションはメモリ リーク地獄に違いないと感じています...

また、メモリ リークを回避する最善の方法として、スマート/共有ポインタを使用することが一般的に受け入れられていることも理解しています。

4

16 に答える 16

460

一般に、参照を返すことは完全に正常であり、常に発生します。

つまり:

int& getInt() {
    int i;
    return i;  // DON'T DO THIS.
}

それはあらゆる種類の悪です。スタック割り当てiはなくなり、何も参照していません。これも悪です:

int& getInt() {
    int* i = new int;
    return *i;  // DON'T DO THIS.
}

クライアントは最終的に奇妙なことをしなければならないからです:

int& myInt = getInt(); // note the &, we cannot lose this reference!
delete &myInt;         // must delete...totally weird and  evil

int oops = getInt(); 
delete &oops; // undefined behavior, we're wrongly deleting a copy, not the original

右辺値参照は参照にすぎないことに注意してください。したがって、すべての悪意のあるアプリケーションは同じままです。

関数のスコープを超えて存在するものを割り当てたい場合は、スマート ポインター (または一般的にはコンテナー) を使用します。

std::unique_ptr<int> getInt() {
    return std::make_unique<int>(0);
}

これで、クライアントはスマート ポインターを格納します。

std::unique_ptr<int> x = getInt();

参照は、ライフタイムがより高いレベルで開かれていることがわかっているものにアクセスする場合にも問題ありません。たとえば、次のようになります。

struct immutableint {
    immutableint(int i) : i_(i) {}

    const int& get() const { return i_; }
private:
    int i_;
};

ここで、参照を返しても問題ないことがわかりi_ます。これは、呼び出し元がクラス インスタンスの有効期間を管理し、i_少なくともその期間は存続するためです。

そしてもちろん、次のことだけでも問題はありません。

int getInt() {
   return 0;
}

寿命を呼び出し元に任せる必要があり、値を計算しているだけの場合。

要約: 呼び出し後にオブジェクトの有効期間が終了しない場合は、参照を返しても問題ありません。

于 2009-04-15T16:58:31.873 に答える
66

いいえ、いいえ、千回いいえ。

悪とは、動的に割り当てられたオブジェクトへの参照を作成し、元のポインターを失うことです。オブジェクトを取得するときnewは、保証されたオブジェクトを保持する義務を負いますdelete

しかし、たとえば、参照operator<<を返さなければならない、または

cout << "foo" << "bar" << "bletch" << endl ;

動作しません。

于 2009-04-15T16:52:34.180 に答える
58

すぐには消えず、所有権の譲渡を意図していない既存のオブジェクトへの参照を返す必要があります。

ローカル変数などへの参照を返さないでください。参照されることはないからです。

関数から独立したものへの参照を返すことができますが、呼び出し元の関数が削除の責任を負うことは期待できません。これは、典型的なoperator[]機能の場合です。

何かを作成している場合は、値またはポインター (通常またはスマート) を返す必要があります。値は呼び出し関数の変数または式に入るため、自由に値を返すことができます。ローカル変数へのポインターは返さないでください。

于 2009-04-15T19:39:29.100 に答える
37

満足のいく答えではないと思うので、2 セント追加します。

次のケースを分析してみましょう。

誤った使用

int& getInt()
{
    int x = 4;
    return x;
}

これは明らかにエラーです

int& x = getInt(); // will refer to garbage

静的変数の使用法

int& getInt()
{
   static int x = 4;
   return x;
}

静的変数はプログラムの存続期間を通じて存在するため、これは正しいことです。

int& x = getInt(); // valid reference, x = 4

これは、Singleton パターンを実装する場合にも非常に一般的です。

class Singleton
{
    public:
        static Singleton& instance()
        {
            static Singleton instance;
            return instance;
        };

        void printHello()
        {
             printf("Hello");
        };

};

使用法:

 Singleton& my_sing = Singleton::instance(); // Valid Singleton instance
 my_sing.printHello();  // "Hello"
    

オペレーター

標準ライブラリ コンテナーは、参照を返す演算子の使用法に大きく依存します。たとえば、

T & operator*();

以下で使用することができます

std::vector<int> x = {1, 2, 3}; // create vector with 3 elements
std::vector<int>::iterator iter = x.begin(); // iterator points to first element (1)
*iter = 2; // modify first element, x = {2, 2, 3} now

内部データへのクイックアクセス

& を使用して内部データにすばやくアクセスできる場合があります

Class Container
{
    private:
        std::vector<int> m_data;

    public:
        std::vector<int>& data()
        {
             return m_data;
        }
}

使用法:

Container cont;
cont.data().push_back(1); // appends element to std::vector<int>
cont.data()[0] // 1

ただし、これは次のような落とし穴につながる可能性があります。

Container* cont = new Container;
std::vector<int>& cont_data = cont->data();
cont_data.push_back(1);
delete cont; // This is bad, because we still have a dangling reference to its internal data!
cont_data[0]; // dangling reference!
于 2016-04-22T12:53:55.000 に答える
14

それは悪ではありません。C++ の多くのことと同様に、正しく使用すれば問題ありませんが、使用時に注意すべき落とし穴がたくさんあります (ローカル変数への参照を返すなど)。

これで実現できる良いことがあります (map[name] = "hello world" など)。

于 2009-04-15T16:51:23.153 に答える
11

「参照を返すことは悪です。なぜなら、単に[私が理解しているように]それはそれを削除するのを見逃しやすくするからです」

違います。参照を返すことは、所有権のセマンティクスを意味するものではありません。つまり、これを行うという理由だけで:

Value& v = thing->getTheValue();

...vが参照するメモリを所有しているという意味ではありません。

ただし、これは恐ろしいコードです。

int& getTheValue()
{
   return *new int;
}

「そのインスタンスにポインタは必要ない」という理由でこのようなことをしている場合は、1)参照が必要な場合はポインタを逆参照するだけで、2)一致する必要があるため、最終的にはポインタが必要になります。削除を伴う新規であり、deleteを呼び出すためのポインターが必要です。

于 2009-04-15T19:28:54.150 に答える
7

次の 2 つのケースがあります。

  • const 参照 -- 場合によっては良いアイデアです。特に重いオブジェクトやプロキシ クラスの場合、コンパイラの最適化

  • 非 const 参照 -- 悪い考えです。カプセル化が壊れることがあります。

どちらも同じ問題を共有しています -- 破壊されたオブジェクトを指している可能性があります...

参照/ポインターを返す必要がある多くの状況では、スマート ポインターを使用することをお勧めします。

また、次の点に注意してください。

正式な規則があります - C++ 標準 (興味がある場合はセクション 13.3.3.1.4) では、一時は const 参照にのみバインドできると述べられています - 非 const 参照を使用しようとすると、コンパイラはこれにフラグを立てる必要があります。エラー。

于 2009-04-15T16:59:00.030 に答える
0

関数の戻り値として参照を使用する方が、関数の戻り値としてポインターを使用するよりもはるかに簡単だと思います。第二に、戻り値が参照する静的変数を使用することは常に安全です。

于 2014-07-29T02:35:35.503 に答える
-2

左辺値としての関数 (別名、非 const 参照を返す) は、C++ から削除する必要があります。それはひどく直感的ではありません。Scott Meyers は、この振る舞いを伴う min() を望んでいました。

min(a,b) = 0;  // What???

これは実際には改善されていません

setmin (a, b, 0);

後者はさらに理にかなっています。

左辺値としての関数が C++ スタイルのストリームにとって重要であることは理解していますが、C++ スタイルのストリームはひどいものであることを指摘しておく価値があります。これを考えているのは私だけではありません...Alexandrescuがより良い方法についての大きな記事を持っていたことを思い出し、boostもより良い型安全なI / Oメソッドを作成しようとしたと思います。

于 2009-04-15T19:52:47.680 に答える
-3

私はそれが本当に悪であるという本当の問題に遭遇しました。基本的に、開発者はベクトル内のオブジェクトへの参照を返しました。それは悪かった!!!

1月に私が書いた完全な詳細: http://developer-resource.blogspot.com/2009/01/pros-and-cons-of-returing-references.html

于 2009-04-15T20:53:40.483 に答える