他のどこにも確かな答えが見つからなかった簡単な簡単な質問です。デフォルトの operator= は、右側にあるすべてのクラスのメンバーの単なる浅いコピーですか?
Class foo {
public:
int a, b, c;
};
foo f1, f2;
...
f1 = f2;
次と同じです。
f1.a = f2.a;
f1.b = f2.b;
f1.c = f2.c;
テストするとこれは正しいようですが、特定のケースを見逃していないことを確認する必要があります。
他のどこにも確かな答えが見つからなかった簡単な簡単な質問です。デフォルトの operator= は、右側にあるすべてのクラスのメンバーの単なる浅いコピーですか?
Class foo {
public:
int a, b, c;
};
foo f1, f2;
...
f1 = f2;
次と同じです。
f1.a = f2.a;
f1.b = f2.b;
f1.c = f2.c;
テストするとこれは正しいようですが、特定のケースを見逃していないことを確認する必要があります。
デフォルトoperator=
はcopyです。各メンバーをコピーします。
浅いコピーと深いコピーの違いは、コピーされるメンバーがポインターなどの間接的なものでない限り発生しません。デフォルトoperator=
に関する限り、「コピー」が何を意味するかはコピーされるメンバー次第であり、それは深いか浅いかのどちらかです。
具体的には、生のポインターをコピーすると、ポインター値がコピーされるだけで、参照先は何もしません。そのため、ポインター メンバーを含むオブジェクトは、デフォルトでシャロー コピーされますoperator=
。
コピー時にクローン操作を実行するスマート ポインターを作成するためのさまざまな取り組みがあるため、生のポインターの代わりにスマート ポインターをどこでも使用すると、デフォルトoperator=
でディープ コピーが実行されます。
オブジェクトがメンバーとして標準コンテナを持っている場合、(たとえば) Java プログラマーがそれをoperator=
「浅いコピー」と言うと混乱する可能性があります。Java では、Vector
メンバーは実際には単なる参照であるため、「浅いコピー」とは、Vector
メンバーが複製されていないことを意味します。ソースと宛先は、同じ基礎となるベクトル オブジェクトを参照します。C++ では、vector
メンバーは参照ではなく実際のオブジェクトであるため、メンバーはその内容と共にコピーされます (vector::operator=
内容が一緒にコピーされることが保証されます)。
データ メンバーがポインターのベクトルである場合、ディープ コピーもシャロー コピーもありません。コピー元オブジェクトとコピー先オブジェクトが別々のベクトルを持っているセミディープ コピーがありますが、それぞれの対応するベクトル要素は依然として同じクローン化されていないオブジェクトを指しています。
はい、デフォルトoperator=
は浅いコピーです。
ちなみに、 と の実際の違いは、クラスがメンバー フィールドとしてポインターshallow copy
を持っている場合に明らかになります。ポインターがない場合、違いはありません (私の知る限り)!deep copy
それらの違いを知るには、次のトピックを参照してください (stackoverflow 自体について)。
はい、オブジェクトをメンバーごとにコピーするだけで、生のポインターに問題が発生する可能性があります。
「浅い」コピーと「深い」コピーは、C や Java よりも C++ では意味がありません。
これを説明するために、Foo
クラスを 3 つint
の から an int
、 an int*
、および a に変更しましたvector<int>
。
#include <iostream>
#include <vector>
class Foo {
public:
int a;
int *b;
std::vector<int> c;
};
using namespace std;
int main() {
Foo f1, f2;
f1.a = 42;
f1.b = new int(42);
f1.c.push_back(42);
f2 = f1;
cout << "f1.b: " << f1.b << " &f1.c[0]: " << &f1.c[0] << endl;
cout << "f2.b: " << f2.b << " &f2.c[0]: " << &f2.c[0] << endl;
}
このプログラムを実行すると、次の出力が得られます。
f1.b: 0x100100080 &f1.c[0]: 0x100100090
f2.b: 0x100100080 &f2.c[0]: 0x1001000a0
int
退屈なので省略しました。int*
しかし、との違いを見てくださいvector<int>
。int*
f1 と f2 では同じです。それはあなたが「浅いコピー」と呼ぶものです。ただし、vector<int>
f1 と f2 では異なります。これは「ディープ コピー」と呼ばれるものです。
ここで実際に起こったことoperator =
は、C++のデフォルトがoperator =
、すべてのメンバーの for が順番に呼び出されたかのように動作することです。operator =
for 、int
、int*
およびその他のプリミティブ型は、単なるバイト単位の浅いコピーです。operator =
forはvector<T>
ディープ コピーを実行します。
したがって、質問に対する答えは、いいえ、C++ の既定の代入演算子は浅いコピーを実行しません。ただし、ディープ コピーも実行しません。C++ の既定の代入演算子は、クラスのメンバーの代入演算子を再帰的に適用します。
いいえ operator=
、コピーは一切行いません。コピー演算子ではなく、代入演算子です。
デフォルトの代入演算子は、各メンバーを割り当てます。
以下のコード スニペットに示すように、STL の = (代入) 演算子はディープ コピーを実行します。
#include <iostream>
#include <stack>
#include <map>
#include <vector>
using namespace std;
int main(int argc, const char * argv[]) {
/* performs deep copy */
map <int, stack<int> > m;
stack <int> s1;
stack <int> s2;
s1.push(10);
cout<<&s1<<" "<<&(s1.top())<<" "<<s1.top()<<endl; //0x7fff5fbfe478 0x100801200 10
m.insert(make_pair(0, s1));
cout<<&m[0]<<" "<<&(m[0].top())<<" "<<m[0].top()<<endl; //0x100104248 0x100803200 10
m[0].top() = 1;
cout<<&m[0]<<" "<<&(m[0].top())<<" "<<m[0].top()<<endl; //0x100104248 0x100803200 1
s2 = m[0];
cout<<&s2<<" "<<&(s2.top())<<" "<<s2.top()<<endl; //0x7fff5fbfe448 0x100804200 1
s2.top() = 5;
cout<<&s2<<" "<<&(s2.top())<<" "<<s2.top()<<endl; //0x7fff5fbfe448 0x100804200 5
cout<<&m[0]<<" "<<&(m[0].top())<<" "<<m[0].top()<<endl; //0x100104248 0x100803200 1
cout<<endl<<endl;
map <int, stack<int*> > mp;
stack <int*> s1p;
stack <int*> s2p;
s1p.push(new int);
cout<<&s1p<<" "<<&(s1p.top())<<" "<<s1p.top()<<endl; //0x7fff5fbfe360 0x100805200 0x100104290
mp.insert(make_pair(0, s1p));
cout<<&mp[0]<<" "<<&(mp[0].top())<<" "<<mp[0].top()<<endl; //0x1001042e8 0x100806200 0x100104290
mp[0].top() = new int;
cout<<&mp[0]<<" "<<&(mp[0].top())<<" "<<mp[0].top()<<endl; //0x1001042e8 0x100806200 0x100104320
s2p = mp[0];
cout<<&s2p<<" "<<&(s2p.top())<<" "<<s2p.top()<<endl; //0x7fff5fbfe330 0x100807200 0x100104320
s2p.top() = new int;
cout<<&s2p<<" "<<&(s2p.top())<<" "<<s2p.top()<<endl; //0x7fff5fbfe330 0x100807200 0x100104340
cout<<&mp[0]<<" "<<&(mp[0].top())<<" "<<mp[0].top()<<endl; //0x1001042e8 0x100806200 0x100104320
cout<<endl<<endl;
vector<int> v1,v2;
vector<int*> v1p, v2p;
v1.push_back(1);
cout<<&v1<<" "<<&v1[0]<<" "<<v1[0]<<endl; //0x7fff5fbfe290 0x100104350 1
v2 = v1;
cout<<&v2<<" "<<&v2[0]<<" "<<v2[0]<<endl; //0x7fff5fbfe278 0x100104360 1
v2[0] = 10;
cout<<&v2<<" "<<&v2[0]<<" "<<v2[0]<<endl; //0x7fff5fbfe278 0x100104360 10
cout<<&v1<<" "<<&v1[0]<<" "<<v1[0]<<endl; //0x7fff5fbfe290 0x100104350 1
cout<<endl<<endl;
v1p.push_back(new int);
cout<<&v1p<<" "<<&v1p[0]<<" "<<v1p[0]<<endl; //0x7fff5fbfe260 0x100104380 0x100104370
v2p = v1p;
cout<<&v2p<<" "<<&v2p[0]<<" "<<v2p[0]<<endl; //0x7fff5fbfe248 0x100104390 0x100104370
v2p[0] = new int;
cout<<&v2p<<" "<<&v2p[0]<<" "<<v2p[0]<<endl; //0x7fff5fbfe248 0x100104390 0x1001043a0
cout<<&v1p<<" "<<&v1p[0]<<" "<<v1p[0]<<endl; //0x7fff5fbfe260 0x100104380 0x100104370
return 0;
}