【VC++2005 MFC】構造体のコピーについて

このQ&Aのポイント
  • 構造体のコピー方法について調べている初心者です。単純に「=」で代入する方法で問題ないのか、先輩に疑問を持たれました。ネットで調べると、型が「int」「char」などの構造体に関しては単純な代入でも問題ないようですが、型が「CString」や構造体の中に構造体が含まれる場合は代入ができないのでしょうか?
  • 先輩からは、「CStringやクラスが含まれる場合は単純な代入ではダメで、各メンバごとに代入するような関数を作る必要がある」と言われました。しかし、私は実際にコーディングやデバッグを行い、単純な代入でも問題なく構造体をコピーできることを確認しています。先輩の言う「メモリが壊れる」ということは本当なのでしょうか?
  • 構造体のコピー方法について調べている初心者です。ネットの情報によると、型が「int」「char」などの基本的なデータ型であれば単純な代入でも問題ないようですが、型が「CString」や構造体の中に構造体が含まれる場合は注意が必要とされています。先輩からは、各メンバごとに代入するような関数を作るべきだとアドバイスを受けましたが、私は実際に単純な代入でも問題なくコピーができることを確認しています。このような場合、どちらの方法が正しいのでしょうか?
回答を見る
  • ベストアンサー

【VC++2005 MFC】構造体のコピーについて

【VC++2005 MFC】構造体のコピーについて 構造体をコピーする時、単純に「=」で代入しているのですが、先輩に 「それじゃコピー出来ないから各メンバごとに代入するような関数作れ」 と言われました。 私自身、C言語の初心者ですが、ネットで調べてみると、単純に「=」で代入出来る ような気がしております。 ただ拝見したサイトに記載されている構造体は型が「int」「char」なのですが、 「CString」を使っていたり、構造体の中に更に構造体が入っていたりする場合も 単純に「=」で代入出来るのでしょうか? (というか、実際にコーディング、デバッグして、コピー出来ている事は確認しているん ですが、先輩いわく、「CStringとかのクラスが含まれている場合はダメだと思う。 メモリが壊れると思う」との事でした。)

  • ya-cha
  • お礼率68% (184/268)

質問者が選んだベストアンサー

  • ベストアンサー
回答No.2

明示的にコピー代入演算子を実装しなかった場合,暗黙に定義されるコピー代入演算子は,各メンバ変数に対して ・クラスであれば再帰的にコピー代入演算子を適用 ・配列であれば各要素を代入 ・スカラ型であればビルトインの代入演算子を適用 となります。 ref) ISO/IEC 14882:2003 (以下IS) 12 Special member functions / 12.8 Copying class objects / paragraph 13 そのため,CStringのメンバ変数があっても,CString::operator=が呼ばれるので問題ないです。 また,コピー代入演算子の明示的な実装を持たないクラスがあった場合でも,それは「暗黙に定義されたコピー代入演算子が存在する」として扱われます。 その結果,メンバ変数は上記の法則によってコピーされます。 # クラスには,構造体や共用体を含みます (IS 9 Classes / paragraph 4) なお,参照型のメンバ変数やconstメンバ変数があった場合,コピー代入演算子がprivateだった場合などは,暗黙に定義されるコピー代入演算子が存在しないためコンパイル時にエラーになります。 ref) IS 12 / 12.8 / paragraph 12

ya-cha
質問者

お礼

とても分かりやすく丁寧にご回答いただき、ありがとうございます。 勉強になりますm(__)m

その他の回答 (2)

  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.3

>「Jiro.Nameはfreeのタイミングで一緒に解放されてしまう」 >で合ってますか? 合っています。 「一緒に」というのは厳密には違いますが。ポインタは同じものを指していますので。 free()した後でTaro.Name = NULL; しても、Jiro.NameはNULLにならずに解放済みのメモリを指したままになっています。 アクセスすれば、高確率でアウトでしょう。 # 解放直後なら触れるかも知れませんが、当然正しくない操作になります。 >構造体の中にはポインタ変数はひとつも無いです。 構造体メンバにクラスが入っていて、その中で…ということもあり得ますので、注意が必要である点には変わりない…かと。 「これから先、構造体のメンバが追加された時にポインタ変数が追加されるかも知れないから…」 ということかも知れませんし。 #2さんが書かれている通り、クラスに対してコピーコンストラクタが正しく実装されていれば大丈夫かと思われます。

ya-cha
質問者

お礼

ご回答ありがとうございますm(__)m とても勉強になります。 今回の構造体には入れ子になっている構造体含めてポインタは存在しないため、 単純な代入処理のままにしておこうと思います。

  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.1

構造体のメンバにポインタ変数がある場合に正しくコピー出来ない場合があります。 strcut Person {  char *Name;  int Age; } Person; Person Taro,Jiro; memset(&Taro, 0, sizeof(Person)); memset(&Jiro, 0, sizeof(Person)); Taro.Name = malloc(20); strcpy(Taro.Name, "太郎"); Taro.Age = 20; としていた時に、 Jiro = Taro; でコピーしたから、 free(Taro.Name); としたら… Jiro.Name はどうなるでしょう?

ya-cha
質問者

補足

早速のご回答ありがとうございます。 構造体の中にはポインタ変数はひとつも無いです。 上記の場合は・・・ 「Jiro.Nameはfreeのタイミングで一緒に解放されてしまう」 で合ってますか?

関連するQ&A

  • 異なる構造体のデータのコピー

    (1)で受け取った構造体のメンバのデータを (2)の構造体のメンバにコピーしたいと考えています。 (1) typedef struct _recvData{ int data01; int data02; char data03; char data 04; char data05; char data 06; char data07; char data08; char data09; char data10; char array01[16]; char array02[16]; } recvData; (2) typedef struct _sendData{ int header; int data01; int data02; char data03; char data 04; char data05; char data 06; char data07; char data08; char data09; char data10; int array01[4]; int array02[4]; } sendData; そこで2点ほどおしえていただきたく、お願い致します。 (1)構造体が微妙に異なるため、各メンバ変数に値をそれぞれ代入していくしか方法がないのでしょうか? (2)array01, array02はデータの型が異なる場合、データのコピーはどのようにしたらよいでしょうか?

  • 構造体のメモリ確保のキャストについて

    構造体のメモリ確保をする際に、処理系はVC++ 6.0なので キャストしなければならないのですがどうすればよいか分かりません。 構造体にはint型とchar型が入っているのですがこの場合はどのようにキャストすればよいのでしょうか? お願いします。

  • C++ 構造体の一括初期化 {0}

    構造体変数に {0} を代入すると、CString は空文字、 intは0に一括で初期化されるようです。 なんでこんなことが出来るのでしょう? {0}は何? 仕組みを教えて下さい!!

  • 構造体を型の異なる構造体に代入

    C言語初心者です。 今回の質問は入力された構造体のメンバのデータを型の異なる構造体に代入したいのですが、毎回コンパイラにおこられてしまいます(汗)具体的には typedef struct MSG{ longint type; int flg; int Dt[64]; }t_msg; このDt[64]を以下の構造体に代入します。 typedef struct SC_MSG{ char a; char b; short c; char d; char e; short f; }t_sc_msg; その際、異なる関数で処理するため、 main(){ foo(&t_msg); }; void foo(t_msg *pt_msgdt){ t_sc_msg = (*pt_msgdt+8); ココがエラーになってしまいます。 何か、根本的な間違いをおかしている気がします。 ご指導の方、宜しくお願いします。 ちなみにOSはLinuxでコンパイラーはgccです。

  • 構造体で・・・・

    構造体は配列を使用せずメモリ領域を獲得する関数を使用すること、 *構造体内部のメンバ名には配列を用いて良い。  という、条件があるのですが場合はどのようにすればよろしいでしょうか? どなたか教えてください。 構造体は以下のようになってます。 /*構造体の定義*/ struct seiseki{   char name[20];   int eig;   int suu;   int kok;   char rank[3]; };

  • 構造体から他の構造体への代入

    現在C言語で簡単なプログラミングを書いているのですが、 構造体(1)(下記参照)から、構造体(2)(下記参照)への代入の方法がわからず悩んでいます。もしよければ手を貸してください!! 標準関数などがないということはわかったので、 地道に代入を行いたいです。 イメージ・・・(data[n].b = moji[n].d;) (1)struct list_kouzou{ int a; char b[30]; char c[8]; }data[100]; (2)struct list_tai{ char d[30]; }moji[15];

  • 動的な構造体配列の初期化

    以下のように構造体を new で動的に確保したときに 構造体の中身(char bbb[10], int ccc)をゼロで初期化したいのですが ZeroMemory を使用するとCArrayのAdd()を使用したときにエラーになってしまいました。 何かよい方法がありましたら教えて下さい。お願いいたします。 # 簡単にイメージですが・・・ typedef struct { CString a; CString b; }aaa_t ; struct s_aaa{ char bbb[10]; int ccc; CArray<aaa_t,aaa_t> m_aaaArray ; } s_aaa *StructB; StructB = new s_aaa [10];

  • C言語の文字列を含んだ構造体

    下記のサイトに構造体のことが書かれています。 http://www.isl.ne.jp/pcsp/beginC/C_Language_14.html その中の (3)構造体の初期化 の記述で  //構造体の型宣言  struct student{   int no; // 学籍番号   char name[256]; // 氏名   int year; // 学年   char student_class[256]; // クラス  }; と書かれています。 次の(4)構造体のデータ参照では、  //構造体の型宣言  struct OLD{   int no; //番号   char *name; //名前   int s_year; //年   char s_class; //クラス  }; と書かれています。 ここで質問です。 前者の名前は char name[256] ですが、 後者の名前は char *name になっています。 name[256] と *name では何が違うのでしょうか? どういうときに使い分けるのでしょうか?

  • C++言語で、構造体のコピーは可能(しても良い)のでしょうか?

    C++言語で、構造体のコピーは可能(しても良い)のでしょうか? 問題がある場合は、なぜだめなのか知りたいです。 構造体は可変長ではありません。 typedef struct kumi { char namae[10]; int ten; }Kumi; Kumi a, b; strcpy(a.namae, "AAA"); a.ten = 50; b = a;

  • 構造体 アドレス

    VC++6 こんにちは。構造体のアドレスを文字列ポインタで操作することに悩んでいます。下にソースの一部を書きます。 typedef struct{   char code[100];   int type; }AAA; typedef struct{   double method[4][3];   int area; }BBB; 複数の構造体があり、 BOOL CTestApp::File_Check(){  AAA aaa; ~  db.DB_regi(2, (char *)&aaa); ~ } void CData::DB_regi(int key, char *buff) {  switch(key){ ~  case 2:   sss.push_back(buff);  //vector<char *> sss;   break; } で、データを登録し、 int CTestApp::Data_Check() { ~  AAA aaa;  db.DB_get(2, (char *)&aaa); ~ } void CData::DB_get(int key, char *buff) {  switch(key){ ~  case 2:   buff = sss[i];   break; ~ } で、構造体のアドレスを取得しようと思ったら、取得できませんでした。 //DB_getの中では、aaa = (AAA *)buff;とすれば指定の構造体を取得できる。 DB_get関数をどのようにしたら、Data_Check()で、登録した構造体を取得できるのか教えてください。長くなってすみません。

専門家に質問してみよう