web-dev-qa-db-ja.com

C ++の `std :: map`に参照を格納できないのはなぜですか?

参照はポインタではなく、オブジェクトへのエイリアスであることを理解しています。しかし、これがプログラマーとして私に何を意味するのか、つまり、内部での参照とは何ですか?

これを理解する最善の方法は、なぜ地図に参照を保存できないのかを理解することだと思います。

私は参照をポインタの構文上のシュガーと考えるのをやめる必要があることを知っていますが、:/の方法がわかりません

42
ng5000

彼らは私が理解しているように、参照は内部ではポインタとして実装されています。それらをマップに格納できない理由は、純粋にセマンティックです。作成時に参照を初期化する必要があり、後で変更することはできません。これは、マップの動作方法とは一致しません。

28
Sebastiaan M

参照は「非constオブジェクトへのconstポインター」と考える必要があります。

MyObject& ~~ MyObject * const

さらに、参照は存在するもののエイリアスとしてのみ構築できます(NULLとは別に推奨されますが、ポインターには必要ありません)。これは、オブジェクトが留まることを保証するものではありません(実際には、参照を介してオブジェクトにアクセスするときにコアがなくなる場合があります)。次のコードを検討してください。

// Falsifying a reference
MyObject& firstProblem = *((MyObject*)0);
firstProblem.do(); // undefined behavior

// Referencing something that exists no more
MyObject* anObject = new MyObject;
MyObject& secondProblem = *anObject;
delete anObject;
secondProblem.do(); // undefined behavior

現在、STLコンテナには2つの要件があります。

  • Tはデフォルトで構成可能でなければなりません(参照はできません)
  • Tは割り当て可能でなければなりません(レフェリーに割り当てることはできますが、参照をリセットすることはできません)。

したがって、STLコンテナーでは、プロキシーまたはポインターを使用する必要があります。

ポインタを使用すると、メモリ処理に問題が生じる可能性があるため、次の操作が必要になる場合があります。

auto_ptrは使用しないでください。右側のオペランドを変更するため、割り当てに問題があります。

それが役に立てば幸い :)

25
Matthieu M.

シンタックスシュガーとの重要な違いは、初期化されたオブジェクト以外のオブジェクトを参照するように参照を変更できないことです。これは、コンテナが含む要素タイプを変更できる必要があるため、マップや他のコンテナに格納できない理由です。

この例として:

A anObject, anotherObject;
A *pointerToA=&anObject;
A &referenceToA=anObject;

// We can change pointerToA so that it points to a different object
pointerToA=&anotherObject;

// But it is not possible to change what referenceToA points to.
// The following code might look as if it does this... but in fact,
// it assigns anotherObject to whatever referenceToA is referring to.
referenceToA=anotherObject;
// Has the same effect as
// anObject=anotherObject;
7
Martin B

実際には、マップで参照を使用できます。奇妙なコンパイルエラーが発生する可能性があるため、大規模なプロジェクトにはお勧めしませんが、

    map<int, int&> no_prob;
    int refered = 666;
    no_prob.insert(std::pair<int, int&>(0, refered)); // works
    no_prob[5] = 777; //wont compile!!! 
    //builds default for 5 then assings which is a problem
    std::cout << no_prob[0] << std::endl; //still a problem
    std::cout << no_prob.at(0) << std::endl; //works!!

マップを使用できますが、正しく使用されることを保証することは困難ですが、これを小さなコード(通常は競争力のある)コードに使用しました

5
Eytan

参照を格納するコンテナhasは、構築時にすべての要素を初期化するため、あまり役に立ちません。

struct container
{
   string& s_;           // string reference
};

int main()
{
   string s { "hello" };
   //container {};       // error - object has an uninitialized reference member
   container c { s };    // Ok
   c.s_ = "bye";
   cout << s;            // prints bye
}

また、いったん初期化されると、コンテナー要素のストレージは変更できません。 s_ will always上記のsのストレージを参照します。

2
tcb

この投稿では、内部でポインタがどのように実装されるかについて説明します- http://www.codeproject.com/KB/cpp/References_in_c__.aspx 。これは、セバスチャンの回答もサポートします。