1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

C++のxcode実装時のエラー Thread 1: signal SIGABRTについて

Posted at

#事の起こり
xcodeでc++のコード実行時、main関数を抜けた際に、
    Thread 1: signal SIGABRT
が起きてしまいました・・・。(簡単なコードなのにショック)
問題のコードはこちら。Runchクラスを2つ用意してコピーして内容表示するだけの簡単なもの。

class Runch{
public:
    string* menu; //ポインタであることに注意
    int value;
    Runch() : menu(new string){}//コンストラクタ
    ~Runch(){//デストラクタ
        delete menu; //フリーストアに確保されたmenuを解放
    }
};

int main(void) {
    Runch Sukiya;
    *Sukiya.menu = "牛丼";
    Sukiya.value = 400;
    //Sukiyaの牛丼は400です。と表示
    cout << "Sukiyaの"<<*Sukiya.menu << "は" << Sukiya.value << "です。"<<endl;
    
    Runch Matuya(Sukiya);//MatuyaにSukiyaをコピー(コピーコンストラクタによるコピー)
    //Matuyaの牛丼は400です。と表示
    cout << "Matuyaの"<<*Matuya.menu << "は" << Matuya.value << "です。"<<endl;
    return 0;
}

#原因
端的に言うと、Runchのメンバのmenuがポインタである事が原因でした。今回のコードで何が起きているのかと言うと・・・

  1. Runch Matuya(Sukiya)とした時に、コピーコンストラクタによってMatuyaのSukiyaの内容がコピーされる。
  2. コピーにより、SukiyaとMatuyaのメンバのmenuは同じアドレスを指すようになる。
  3. main関数終了時にRunchで明示的に定義したデストラクタが働き、フリーストアに確保されたMatuyaとSukiyaのmenuを解放する。

と言うことが起きています。一見なんの不備もないように思われますが、実は3で問題が起きていました。

デストラクタは基本的に、そのクラスが不要になった時(今回だったらmain関数が終わった時)に働くものです。今回は、SukiyaとMatuyaの二つのクラスがあるのでmain関数の終わりにはSukiyaとMatuyaのそれぞれの2つのコンストラクタが働いて、フリーストアに確保されているmenuを解放しようとします。
しかし、ここで2つのクラスのmenuは同じアドレスを指しています。すなわち、同じ物を2回解放しようとしてします。これにより、
Thread 1: signal SIGABRT
によるエラー終了が発生していたようです。

#対策
コピーコンストラクタを次のように明示的に定義して、コピーの際に、menuのアドレスを直でコピーしないようにしました。

class Runch{
public:
    string* menu; //ポインタであることに注意
    int value;
    Runch() : menu(new string){}//コンストラクタ
    ~Runch(){//デストラクタ
        delete menu; //フリーストアに確保されたmenuを解放
    }
    Runch(const Runch& x){//コピーコンストラクタを明示
        string oldMenu = *x.menu; //コピー元のmenuを一時避難
        menu= new string(oldMenu);//新たなmenuをフリーストアに確保
        value = x.value;
    }

};

int main(void) {
    Runch Sukiya;
    *Sukiya.menu = "牛丼";
    Sukiya.value = 400;
    //Sukiyaの牛丼は400です。と表示
    cout << "Sukiyaの"<<*Sukiya.menu << "は" << Sukiya.value << "です。"<<endl;
    
    Runch Matuya(Sukiya);//MatuyaにSukiyaをコピー(コピーコンストラクタによるコピー)
    //Matuyaの牛丼は400です。と表示
    cout << "Matuyaの"<<*Matuya.menu << "は" << Matuya.value << "です。"<<endl;
    return 0;
}

このようにすると、Runch Matuya(Sukiya)とした時に、明示的に定義したコピーコンストラクタが働き、Sukiyaのmenu(Gyudon)がoldMenuとしてコピーされ、新たにフリーストアに確保したMatuyaのmenuにコピーされます。
こうすると、SukiyaとMatuyaのメンバ menuはそれぞれ別のアドレスを指すのでデストラクタによる2重解放を防ぐことができ、Thread 1: signal SIGABRTを消すことができました。

#まとめ
今回調べてみて分かったことですが、Thread 1: signal SIGABRTは今回のようなフリーストアに確保した資源の2重解放以外の原因でも発生するようです。(一つのエラーコードに複数の原因があるのはいかがなものか・・・)
今回のように2重解放だけが原因でないかもしれませんが、Thread 1: signal SIGABRTに出くわした時は、2重解放していないかどうか疑ってみてはどうでしょうか.

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?