• ベストアンサー

デストラクタについて

#include <iostream> #include <string> using namespace std; #define NUM 2 //登録人数 class Person{ char *name; int *age; char *hobby; public: Person() { name = new char; age = new int; hobby= new char; } void Set(char *n,int a,char *h) { name=n; *age=a; hobby=h; } char *Get_name(void) { return name; } int Get_age(void) { return *age; } char *Get_hobby(void) { return hobby; } ~Person() { cout<<name<<"のデストラクタ\n"; delete [] name; delete age; delete [] hobby; } }; int main(void) { Person *p; int i; p=new Person[NUM]; p[0].Set("永嶋",21,"映画鑑賞"); p[1].Set("平林",54,"車"); for(i=0;i<NUM;i++){ cout<<"\n名前:"<<p[i].Get_name(); cout<<"\n年齢:"<<p[i].Get_age(); cout<<"\n趣味:"<<p[i].Get_hobby()<<"\n"; } delete [] p; return 0; } というプログラムを作成したのですが デストラクタの3つのdeleteがおかしいようなのですが どのような部分が問題となっているのでしょうか? 回答・アドバイス宜しくお願いいたします。

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

  • ベストアンサー
  • kmb01
  • ベストアンサー率45% (63/138)
回答No.5

No2補足の回答です。 >Setのメソッドの中にある二つのif文は何のために有るのでしょうか? > >初心者が言うのは生意気ですが >デストラクタの部分でdeleteすれば良いのではないのでしょうか? 同じオブジェクトに対して複数回Setが呼び出されたときに、 以前に確保したname,hobby領域を開放して、新しいname,hobbyの領域を確保しています。 これを行わずいきなりname=new char[strlen(n)+1];とやると、 nameが上書きされるため古いnameが開放できなくなります。 同じオブジェクトに対してSetは絶対に1回しか呼ばないならばこの処理は不要ですが、 そういった条件を設けることはあまり望ましくないと思います。

weasel
質問者

お礼

やっと意味が分りました。 再度回答ありがとうございました。

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (4)

  • KamoPlat
  • ベストアンサー率46% (23/50)
回答No.4

眠い頭で回答してしまったのでちょっと日本語と用語の使い方がおかしいですね。申し訳ありませんでした。 もしコンストラクタのnewが変数の型の初期値で初期化したいなら、 age = int(); のようにするか、初期化リストを使うと良いですよ。 Person() :name (NULL) , age (0) , hobby (NULL) { } それとも、 *Get_hobby()とかをSet()するまえに呼び出したときの保険なら、 Get()の方で判定して return ""; としてやるのもいいかも。ただし、const char*ですね、コレは。 そうでなければ、毎回きちんとSet()が呼び出されるたびにnew/deleteして メモリ管理しなければなりません。(他の方の仰っているstringもそれを自動で やってくれるものです)

weasel
質問者

お礼

アドバイス有難うございます。 いろいろ勉強できてためになります。

全文を見る
すると、全ての回答が全文表示されます。
  • hidebu-
  • ベストアンサー率53% (45/84)
回答No.3

まずコンストラクタの Person() { name = new char; age = new int; hobby= new char; } でヒープ領域にメモリ確保している意図がわかりません。 この処理ロジックだと、別にヒープにメモリ確保する必要なしかと。 ------------------------------------- #include <iostream> #include <string> using namespace std; #define NUM 2 //登録人数 class Person{ char *name; int age; char *hobby; public: Person() { } void Set(char *n,int a,char *h) { name=n; age=a; hobby=h; } char *Get_name(void) { return name; } int Get_age(void) { return age; } char *Get_hobby(void) { return hobby; } ~Person() { cout<<name<<"のデストラクタ\n"; } }; int main(void) { Person *p; int i; p=new Person[NUM]; p[0].Set("永嶋",21,"映画鑑賞"); p[1].Set("平林",54,"車"); for(i=0;i<NUM;i++){ cout<<"\n名前:"<<p[i].Get_name(); cout<<"\n年齢:"<<p[i].Get_age(); cout<<"\n趣味:"<<p[i].Get_hobby()<<"\n"; } delete [] p; return 0; } ------------------------------------- といった感じですかね。 よくわからないうちにむやみに多用するとリークおこしまくりますよ^^;

weasel
質問者

お礼

自分でも必要ないとは思っていたのですが 正確には私が書いたように白とは書いてないのですが メソッドの中でnew演算子を使う事が 条件だったのであのようになってしまいました。 今後気をつけます。 回答有難うございました。

全文を見る
すると、全ての回答が全文表示されます。
  • kmb01
  • ベストアンサー率45% (63/138)
回答No.2

char*型の代入はポインタ値がコピーされるだけで、その指す先がコピーされるわけではありません。 関数呼び出しでも文字列そのものが渡されるわけではなく先頭アドレスが渡されます。 上の例だと p[0].Set("永嶋",21,"映画鑑賞"); としている部分では、メモリ上のどこかに永嶋、映画鑑賞というデータが書き込まれた領域が作成されていて、 その先頭アドレスが例えば100,200だとすると、関数呼び出し部分は p[0].Set(100,21,200); と呼び出されることになります。 呼び出されるSet内のname=n;はname=100;ということで、 nameに入っていたコンストラクタでnewした領域のアドレスは失われます。 そしてデストラクタでdeleteする領域がnewで確保した領域でないためエラーとなります。 また、name = new char;は1文字分しか領域を確保していないという間違いもあります。 解決案はstring型を使うか、以下のようにSet時に領域を確保する方法があります。 class Person{ char *name; int age;//ポインタにする意味がないと思う char *hobby; public: Person() { name = NULL; hobby= NULL; } void Set(char *n,int a,char *h) { if (name) delete[] name; name=new char[strlen(n)+1]; strcpy(name, n); age=a; if (hobby) {delete[] hobby;} hobby=new char[strlen(h)+1]; strcpy(hobby, h); }

weasel
質問者

お礼

回答有難うございました。 Setのメソッドの中にある二つのif文は何のために有るのでしょうか? 初心者が言うのは生意気ですが デストラクタの部分でdeleteすれば良いのではないのでしょうか? 見当はずれな事を聞いているかもしれませんが 良い機会なので教えていただければ幸いです。 宜しくお願いします。

全文を見る
すると、全ての回答が全文表示されます。
  • KamoPlat
  • ベストアンサー率46% (23/50)
回答No.1

いろいろまずいと思います。 まず、コンストラクタで new char; などとしているのに、デストラクタで delete [] name; などとなっています。 これはまずいです。 それと、 Set()でnに指定されるのはnewされた文字列へのポインタではなく ヒープのアドレスです。 new / deleteとnew [] / delete [] は対応させないと。

weasel
質問者

お礼

回答有難うございます。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • 配列の中を変更

    入力したnameに、入力したageの数だけ文字を進める(例えばnameがOda、ageが12→表示結果がAmp)にする関数を作成しようとしたのですが、やり方がまったくわかりません。 そもそもこのような場合、文字1つ1つに別の配列を使わなければならないのでしょうか? #include <stdio.h> #define N 1 #define NAME 20 typedef struct{ char name[NAME]; char age; } person; int main(void){ int i; person persons[N]; for(i=0;i<N;i++){ printf("name > "); scanf("%s" , persons[i].name); printf("age > "); scanf("%d" , &persons[i].age); } for(i=0;i<N;i++){ printf("name = %s\n" , persons[i].name); printf("age = %d\n" , persons[i].age); } return 0; }

  • C言語 家系図

    問題 構造体personを以下のように仮定する。 struct person { int age; char name[20]; struct person *father; struct person *mother; }; この構造体の表す人の名前、年齢、その人の父親の名前、およびその人の母親の名前を出力する関数 void print_person(struct person *p) を作成せよ。出力の形式は name: 本人の名前 age: 本人の年齢 father: 父親の名前 mother: 母親の名前 となるようにすること。 また、ポインタ father や mother の値が NULL のときには、名前のかわりに unknown と出力するようにせよ。 以上が問題なのですが自分でプログラムを作ってみたところ実行したら、エラーになって矯正終了されてしまいました。 以下が私の作ったプログラムです。 #include <stdio.h> struct person { int age; char name[20]; struct person *father; struct person *mother; }; void set_name(struct person *p, char name[]) { int i; i = 0; while (name[i] != 0) { p->name[i] = name[i]; i++; } p->name[i] = 0; } void print_person(struct person *p) { printf("name:%s", p->name); printf("age:%s\n",p->age); if(p->father != NULL){ printf("father:%s\n",p->father); } else{ printf("unknown"); } if(p->mother != NULL){ printf("mother:%s\n",p->mother); } else{ printf("unknown"); } } int main(void) { struct person me, dad, mom; set_name(&me, "Michael"); me.age = 16; me.father = &dad; me.mother = &mom; set_name(&dad, "David"); dad.age = 38; dad.father = NULL; dad.mother = NULL; set_name(&mom, "Susan"); mom.age = 36; mom.father = NULL; mom.mother = NULL; print_person(&me); print_person(&dad); print_person(&mom); return (0); } どこが違うのか教えていただけないでしょうか?

  • プログラミング構造体について。

    include<stdio.h> #include<stdlib.h> #include<string.h> struct person{ char name[10]; int gender; int age; }; void printPersonList(struct person *person_p, int size); void outputPersonList(struct person *person_p, int size); double getAverageOfAge(struct person *person_p, int size); int countMales(struct person *person_p, int size); int countFemales(struct person *person_p, int size); int main(void){ struct person *person_p; int i, count, gender, age, maleCount, femaleCount; char name[20]; double average; printf("登録する人数を入力してください。\n"); scanf("%d", &count); person_p = (struct person*)malloc(sizeof(struct person)* count); for(i=0; i < count; i++){ printf("名前・性別(男性:0, 女性:1)・年齢をスペース区切りで入力してください。\n"); scanf("%s %d %d", name, &gender, &age); strcpy((person_p + i) -> name, name); (person_p + i) -> gender = gender; (person_p + i) -> age = age; } printPersonList(person_p, count); outputPersonList(person_p, count); average = getAverageOfAge(person_p, count); printf("平均年齢:%f\n", average); maleCount = countMales(person_p, count); femaleCount = countFemales(person_p, count); printf("男性:%d名, 女性:%d名\n", maleCount, femaleCount); free(person_p); return 1; } void printPersonList(struct person *person_p, int size){ int i; printf("登録リスト\n"); printf(" name | gender | age\n"); printf("----------+--------+-----\n"); for(i=0; i < size; i++){ printf("%10s | %1d | %2d\n", (person_p + i) -> name, (person_p + i) -> gender, (person_p + i) -> age); } } void outputPersonList(struct person *person_p, int size){ FILE *output; int i; if((output = fopen("meibo.c", "w")) == NULL){ printf("meibo.cを開けませんでした。\n"); return; } for(i=0; i < size; i++){ fprintf(output, "%s, %d, %d\n", (person_p + i) -> name, (person_p + i) -> gender, (person_p + i) -> age); } fclose(output); } 残り3つの関数をすべて定義する(それぞれ10行程度) getAverageOfAge, countMales, countFemales どう定義すればいいのか教えてください。お願いします。

  • scanfの\nの意味

    タイトルの通りです。 #include<stdio.h> struct Person{ char name[100]; char gender; int age; }; int main(void) { struct Person person1; printf("名前は:"); scanf("%s",person1.name); printf("\n年齢は:"); scanf("%d",&person1.age); printf("\n性別は:"); scanf("\n%c",&person1.gender); printf("\n{name=%s,age=%d,gender=%c}",person1.name,person1.age,person1.gender); return 0; } 上記において aaa , 11 , M と入力すると {name=aaa,age=11,gender=M} と表示されますが、 scanf("\n%c",&person1.gender); を scanf("%c",&person1.gender); に変えると {name=aaa,age=11,gender= } となってしまいます。 この理由と、/nの意味を教えてください。

  • プログラミングの質問です

    #include<stdio.h> #include<stdlib.h> #include<string.h> struct person{ char name[10]; int gender; int age; }; void printPersonList(struct person *person_p, int size); void outputPersonList(struct person *person_p, int size); double getAverageOfAge(struct person *person_p, int size); int countMales(struct person *person_p, int size); int countFemales(struct person *person_p, int size); int main(void){ struct person *person_p; int i, count, gender, age, maleCount, femaleCount; char name[20]; double average; printf("登録する人数を入力してください。\n"); scanf("%d", &count); person_p = (struct person*)malloc(sizeof(struct person)* count); for(i=0; i < count; i++){ printf("名前・性別(男性:0, 女性:1)・年齢をスペース区切りで入力してください。\n"); scanf("%s %d %d", name, &gender, &age); strcpy((person_p + i) -> name, name); (person_p + i) -> gender = gender; (person_p + i) -> age = age; } printPersonList(person_p, count); outputPersonList(person_p, count); average = getAverageOfAge(person_p, count); printf("平均年齢:%f\n", average); maleCount = countMales(person_p, count); femaleCount = countFemales(person_p, count); printf("男性:%d名, 女性:%d名\n", maleCount, femaleCount); free(person_p); return 1; } void printPersonList(struct person *person_p, int size){ int i; printf("登録リスト\n"); printf(" name | gender | age\n"); printf("----------+--------+-----\n"); for(i=0; i < size; i++){ printf("%10s | %1d | %2d\n", (person_p + i) -> name, (person_p + i) -> gender, (person_p + i) -> age); } } void outputPersonList(struct person *person_p, int size){ FILE *output; int i; if((output = fopen("meibo.c", "w")) == NULL){ printf("meibo.cを開けませんでした。\n"); return; } for(i=0; i < size; i++){ fprintf(output, "%s, %d, %d\n", (person_p + i) -> name, (person_p + i) -> gender, (person_p + i) -> age); } fclose(output); } 上は、「キーボードで入力した個人データ(名前、性別、年齢)を構造体に入れて、一覧を画面に出し、かつ、ファイルに書き出す」ことをするプログラムです。これを名前が辞書順になるようにしたいです。どう書くのか教えてください。

  • クロージャ

    javascriptのクロージャについて。 クロージャにnewは必要ですか? コンストラクタであれば、newでオブジェクトを生成しますが、クロージャはどうでしょうか? クロージャ-------------------- function Person(n, a){ var name = n; var age = a; return { getName: function() { return name; }, setAge: function(i){ if( 0<= i ){ age = i; } }, getAge: function(){ return age; } } } var p = new Person('Hanako', 3); // new を付けなくても生成できる

  • C# override

    某C#の入門書のサンプルですが、overrideがよくわかりません。 using System; using System.Collections.Generic; using System.Text; namespace PersonList {   class Person   {     public string name;     public int age;     public Person(string nam, int ag)     {       name = nam;       age = ag;     }     public override string ToString()     {       return String.Format("{0}({1})", name, age);     }   }   class Program   {     static void Main(string[] args)     {       List<Person> p = new List<Person>();       p.Add(new Person("Pochi", 3));       p.Add(new Person("Kenta", 5));       p.Add(new Person("Mari", 4));       p.Add(new Person("Wanko", 1));       p.Add(new Person("Doggy", 4));       p.ForEach(Console.WriteLine);     }   } } 1.overrideをしないと 「PersonList.Person」が出力されてしまうのですが  なぜToString()をoverrideするのかがわかりません。 2.override しないですべての内容を出力するためにはどうしたら  いいのでしょうか?

  • コンポジション コンストラクタに引数がある場合

    class Person{ public String name_; public int age_; public Person(String n,int a){ name_ = n; age_ = a; } } class Student{ public Person person_; public int grade_; public Student(Person p,int g){ person_ = new Person("MOTO",2); grade_ = g; } } public class Samconp2{ public static void main(String[] args){ Student asaya_ = new Student(p,0); } System.out.println(asaya_.person_.name+asaya_.person_.age_+asaya_.grade__); } 3のプログラムを見るようにコンストラクタに引数使い、又継承を使わないでPerson クラスのname_ age_ それを拡張したStudetクラスのgrade_をmain関数で表したいのですが(希望としてはname_ "Moto" age_ 2 grade_ 0) 結果としては、System.out.println(asaya_.personn_.name_ + asaya_.person_.age_ +asaya_grade_);で<identifierがありません>となります。 まだ初心者で良く分りません。解決方法をお願いします。

    • ベストアンサー
    • Java
  • ファイル読込時に構造体の文字列ポインタに割当てたいと

    ファイル読込時に構造体の文字列ポインタに割当てたいと思っています。 (new 演算子を使用します。) 文字列の長さが不定です。 どうすれば、文字列の長さを知ることができますか? 以下のようなところまでは作れましたが、 困っています。 void loaddata()のfscanf関数の部分です。 ほかにも関数の void outputdata() void deletedata() がありますが、長いので省略しました。 ********************************************************** #include<stdio.h> #include<string.h> class data { public: struct basic { char *name; int age; struct basic *next; }; private: struct basic *base; struct basic *base_top; int cnt; public: data::data() { cnt=0; } void inputdata(char *name,int age) { if(cnt==0) { base=new basic; base_top=base; base->age=age; int len=strlen(name); base->name=new char[len+1]; strcpy(base->name,name); cnt++; } else { base->next=new basic; base=base->next; base->age=age; int len=strlen(name); base->name=new char[len+1]; strcpy(base->name,name); cnt++; } } void savedata() { base=base_top; FILE *fp; fp=fopen("dat.txt","w"); for(int i=0;i<cnt;i++) { fprintf(fp,"%s\t%d\n",base->name,base->age); base=base->next; } fclose(fp); } void loaddata() { if(cnt!=0){deletedata();} cnt=0; FILE *fp; fp=fopen("dat.txt","r"); while(1) { fscanf(fp,"%s\t%d\n",base->name,base->age); } } };

  • アルゴリズム 線形リスト

    最近リストについて習い始めました。入力したデータと同順に並ぶリストを作成しようと思い、コードを打ったのですが…動作中止の表示がでてしまいました。どこが間違っているのか、ずっと悪戦苦闘して組んでいるのですが、全く出口が見えてきません。何が間違えているのか、はたまた根本的に違うのか、ご指導して頂けると有難いです。 以下、コードです。 #include <stdio.h> #include <stdlib.h> #include <string.h> struct hito{ char name[20]; int age; struct hito *next; }; void main(void){ struct hito *p, *head, *dummy; char new_name[20]; int new_age; dummy = (struct hito *)malloc(sizeof(struct hito)); head = dummy; dummy->next = p; dummy = p; while (scanf("%s %d" , new_name, &new_age) != EOF) { p = (struct hito *)malloc(sizeof(struct hito)); strcpy(p->name, new_name); p->age = new_age; p->next = head; head = p; } while(p != NULL) { printf("\t%-20s %3d\n" , p->name, p->age); p = p->next; } }

このQ&Aのポイント
  • 友人が助けてくれないという状況について悩んでいます。彼らを友人と呼ぶべきか、それとも別の言葉で表現すべきか迷っています。
  • 私は友人が困っていたら助けるつもりですが、そんな思いやりを持たない友人からは、友人としての関係性に疑問を感じます。
  • 最近、仕事の疲れや自己価値感の低さに悩んでいます。落ち着く方法や話す相手の選び方についてもアドバイスをいただきたいです。
回答を見る

専門家に質問してみよう