2010-11-29 11 views
9

C++の参照セマンティクスに関してちょっと混乱します。const以外のオブジェクトをconst参照から初期化するときのコピーを防止します

class foo 
{ 
private: 
    std::map<int, int> stuff; 
public: 
    const std::map<int, int>& getStuff() 
    { 
     return stuff; 
    } 
}; 

そして、次のように私はそれを使用します:私はconst参照を返すクラスがあるとし

foo f; 
std::map<int, int> s = f.getStuff(); 
:罰金ですが、私はそれを使用した場合、次のように

foo f; 
const std::map<int, int>& s = f.getStuff(); 

正確にはどうなりますか?

私が正しく理解していれば、stuffのconst参照が返され、コピーがsに作成され、そこで私は大混乱を招く可能性があります。これを避ける方法はありますか?

編集:

だからここに呼ばれているコピーコンストラクタを回避するための手立てはこれがstd::map<int, int>コピーコンストラクタを呼び出し、コピーを作成します

+0

AFAIKコピーコンストラクタが呼び出され、これを回避する方法はありません。 – Lagerbaer

+1

あなたはそうです。しかし、あなたがそれをやめないようにしたいのであれば、いつでも 's' constを作ることができます。また、 's'をconst refにすることは、' f'がその間に生きていることを確認する必要があることを意味します。もしそれが以前に宣言された自動変数であれば自動的に起こりますが、ヒープ上に作成されました。 –

+2

しかし、 's'で行った変更は、元のオブジェクト' stuff'には影響しません。それであなたはどのように影響を受けますか? – Naveen

答えて

5

短い回答:いいえ、あなたはそれを防ぐことはできません。クライアントはmodできません元のifyですが、クライアントにマップへの読み取りアクセス権を与えると、クライアントはその情報で愚かなことをしない責任があります。クラスはそれを防ぐことはできません。

長めの回答:多分、本当はそうではありません。本当にコピーを困難にしたい場合は、プライベートコピーコンストラクタと代入演算子を使用してクラス内のマップをラップすることができます。その方法では、sの割り当ては不正です(コンパイラによって拒否されます)。クライアントは断片的なマップの要素を読み取って新しいマップを手動でコピーすることができますが、これを防止する唯一の方法は、ラッパークラスの読み取りアクセスを制限することですgetStuffの目的を破る。

+0

ラッパー!はい、それは私が必要なものです、ありがとう!!!私の脳は今夜完全に揚げられています:s –

4
std::map<int, int> s = f.getStuff(); 

...とにかくのstd ::マップのため、ありませんオブジェクトのstuffマップの内容は新しいマップsにコピーされます。

sは元のオブジェクトと新しいオブジェクトが同じ内容を持っていることを除けば、元のオブジェクトとはまったく無関係な新しいオブジェクトであるため、元のオブジェクトと混乱することはありません。

foo::getStuff()によって返されたconst参照を使用してstuffマップを使用すると、合法的に大混乱を招くことはありません。マップを変更できる唯一の方法はconst_castで、const_castで得られたポインタまたは参照を使用してオブジェクトを変更すると、未定義の動作が発生する可能性があります。

+0

非常に多くの票を驚かせ、「これを避ける方法はありますか」という質問に答えないという事実を喚起する。 – Chubsdad

+0

十分に公正だと思いますが、参照を使うか、const const :: map s = f.getStuff();を実行してください。 –

+1

@Chubsdad:いいえ、私はOPのmeta-questionに "コードは本当に機能しますか?"元のオブジェクトが完全にコピーされ、新しいオブジェクトが元のオブジェクトとまったく無関係であることを理解したら、同じ内容を持つことを除いては簡単です。 –

1

はい、ご理解ください。これは、コピーの初期化によって何も行われず、コピーコンストラクタの使用を伴います。これは、表示されたコードスニペットによって要求されているものなので、このコピーを避ける方法はありません。

コピーに大混乱を起こしても、心配はいりません。オリジナルはまだ安全です。懸念は、コピーを作成するプロセスが混乱を招く可能性がある場合にのみ発生しますが、それは別の問題です。

C++ 03関連文献:

$ 8.5/12 - 「 は引数渡しで発生し、初期化、機能 リターン、例外(15.3)を例外処理(15.1)、 を投げ、そして 中括弧で囲まれたイニシャライザリスト (8.5.1)はコピー初期化 と呼ばれ、形式T x = aと同等です;

$ 8.5/14「の初期化が 直接初期化がある場合、またはそれが コピー初期設定がある場合は、ソース タイプの CV-修飾されていないバージョンが同じクラス、または 派生クラスのはここ、 宛先クラスのクラスは、 とみなされます。適用可能な コンストラクタは、 (13.3.1.3)で列挙され、最適なものは、過負荷解決(13.3)によって から選択されます。 このように選択されたコンストラクタは と呼ばれ、 イニシャライザ式を 引数としてオブジェクトを初期化します。コンストラクタ が適用されない、またはオーバーロードの解決があいまい であれば、初期化は が病気に形成されている「

+2

参照が意味論に関して少し混乱している場合、標準を引用することはおそらく少し威圧しているでしょう... –

0

うん、これはマップのコピーを作成します。あなたの質問については

- 。。によって異なりあなたがあなたが宣言したクラスであれば、コピーコンストラクタまたはoperator =をプライベートにすることはできませんが、これはあなたにはかなりのことを禁止します。

関連する問題