質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.21%

C++ コピーコンストラクタの使用方法

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,501

saito.kaz

score 76

前提・実現したいこと

showdataに値渡しが行われた際に、デストラクタが発生するのを防ぐために、コピーコンストラクタを実装しましたが、エラーが発生し解決できません。
エラー箇所を解決できないので、すいませんが教えてください。

発生している問題・エラーメッセージ

エラー文は下記のものだけです。
Runtime error(Exit status:134(Abort signal from abort(3)))

ソースコード

<ヘッダー文>
class Worker{
 public:
   int number;
   char* name;
   double salary;
   Worker();
  Worker(const Worker &obj);
   ~Worker();
};
<メイン文>
#include <iostream>
#include "Worker.h"
using namespace std;

Worker::Worker(){
 name = new char[80];
 cout<< " This is Constructor "  << "\n";
 strcpy(name, "undifined");
 number = 0;
 salary = 0;
}


Worker::Worker(const Worker &obj){
    cout<< " This is Copy Constructor "  << "\n";
    name = new char[80];
    name = obj.name;
    this->number = obj.number;
    this->salary = obj.salary;
};


Worker::~Worker(){
    delete[] name;
    cout << "デコンストラクタ" << "\n";
}


void ShowData(Worker w2){
   cout << "name = " << w2.name << "\n";
   strcpy(w2.name,"AVD");
   cout << "name = " << w2.name << "\n";
   cout << "number = " << w2.number << "\n";
   cout << "salary = " << w2.salary << "\n";
}

int main(){
    Worker w1;
    strcpy(w1.name,"Takayuki");
    w1.number =10;
    w1.salary = 100;
    cout << " Before shwodata" << "\n";
    ShowData(w1);
    cout << " After shwodata" << "\n";

    return 0;
}

補足情報(言語/FW/ツール等のバージョンなど)

paiza.io

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

+4

今回質問されているエラーについて何も記載されていませんので、怪しいところの指摘のみですが、コピーコンストラクタを書くとしたら

Worker::Worker(const Worker &obj){
    cout<< " This is Copy Constructor "  << "\n";
    name = new char[80];
    strncpy(name, obj.name, 80);
    this->number = obj.number;
    this->salary = obj.salary;
};


と書かないと、コピーされたオブジェクトを破棄する際に、もとのnameメンバも解放してしまいますよ。

あと、ちょっと苦言で申し訳ないですが、エラーの内容が判っているのは質問者さんのみで、ここを読んでいる人にはどういう操作をしたらエラーになった等の状況がさっぱりわかりません。エラーメッセージだけでなく、そういった情報もできるだけ書いてもらった方が的確な回答が集まりやすいです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/01/21 14:26

    今回、エラー文が表示されず、上記のエラーメッセージのところに記載してある文のみでした。お手数をおかけし、申し訳ありません。

    キャンセル

  • 2016/01/21 15:01

    KoichiSugiyamaさんの回答でFinal Answerと思いますので、こちらで補足させて下さい。

    TAKAYUKI_MIWAさん、先の質問からのトライですね。
    下記はコンパイラが自動生成するものと事実上同じですので、コピーコンストラクタの生成をコンパイラに任せた場合と同じ結果になるのですよ。

    > name = obj.name;

    後、私のサンプル・コードでは初期化子を使ってました。まだC++初めて一週間の方に提示するのは適切でなかったかも。私が初期化子の存在を知ったのはC++を初めてたぶん10年後くらいだったような...ごめんなさい。

    下記に初期化子を含めてC++のクラス定義について説明がありました。
    http://homepage2.nifty.com/well/Class.html
    中々良いサイトですので、時間がとれたら見てみることをお薦めします。

    キャンセル

checkベストアンサー

+3

コピーコンストラクタの以下の実装は問題があります。

name = new char[80];
name = obj.name;

name = new char[80]
により、新しいメモリをヒープ領域から確保し、その先頭アドレスが name に入りました。

ところが、
name = obj.name

として、name で保持していたアドレス値が、コピー元のnameのアドレス値に上書きされてます。
※コピーコンストラクタで渡される obj は、コピー元のインスタンスです。

先ほど確保したメモリのアドレスが行方不明になってしまうのはわかりますか?
そのため、先ほど確保したメモリを解放(delete)する機会が無くなってしまいます。

このオブジェクトがメソッドに渡されるたびに、解放されることのないメモリが確保されていくので、
やがてメモリリークを起こすことになります。

さらに、
name = obj.name 
としているため、この関数終了のときに呼ばれるデストラクタで、コピー元の name が指し示すメモリが解放されます。
mainロジック完了の際に、もともとのオブジェクトも、デストラクタにより同一の name が指し示すメモリを解放してしまうため、2重解放になってしまいます。

これを解決するために、KoichiSugiyamaさんがご提示されているようにしなければなりません。

name = new char[80];
strncpy(name, obj.name, 80);


name = new char[80]
によって、新しいメモリ領域を割り当てたあと、strcpy によって、コピー元のobjのname の内容を、新しいメモリ領域にコピーしています。
(strcpyはバッファ上限を指定しないため、セキュリティ上脆弱です。利用しないことが推奨されており、KoichiSugiyamaさんはstrncpyにされています)

name には、新しく割り当てたメモリのアドレス値が入っていることを確認してください。

このメソッドが完了した際に呼ばれるデストラクタでは、
delete name
によって、新しく割り当てたメモリ領域が解放されることになります。

ポインタまわりは、難しいかもしれませんが、必ず腑に落ちるまで学習しておいたほうが良いと思います。
私は、こちらの書籍で理解できましたので、ご参考までに紹介させていただきます。

C言語ポインタ完全制覇

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/01/21 14:57

    ありがとうございます。
    とてもご参考になりました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.21%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る