掲示板利用宣言

 次のフォームをすべてチェックしてからご利用ください。

 私は

 題名と投稿者名は具体的に書きます。
 課題の丸投げはしません。
 ソースの添付は「HTML変換ツール」で字下げします。
 返信の引用は最小限にします。
 環境(OSとコンパイラ)や症状は具体的に詳しく書きます。
 返信の付いた投稿は削除しません。
 マルチポスト(多重投稿)はしません。

掲示板2

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧

No.29894

演算子オーバーロード後デストラクタでセグメントエラー
投稿者---Mr.Boo(2007/03/09 10:15:19)


環境その1
Windows XP HOME SP4
Borland C++ 5.5.1
環境その2
Fedora Core 5
gcc 4.1.1

新人研修用に演習課題を作成しておりますが、バグの原因が解らず困っております。
どなたか、知恵を貸していただけませんでしょうか。

以下のプログラム実行時に、最初のデストラクタでdeleteするとセグメントエラーが発生します。
オブジェクトy1をy4に代入する演算子オーバーロード実行部分をコメントアウトすると、
エラーが発生しなくるのですが、デバッガで確認しても、
演算子オーバーロード部でのnewされるポインタとdeleteする直前のポインタには変化はありませんでしたし、
ポインタの中身に問題は見られませんでした。
どこを見落としているのか、どうかご教授下さい。
#include<iostream>
#include<cstring>
using namespace std;

class strtype{
    char *p;
    int len;
public:
    strtype(char* s);
    strtype();
    ~strtype();
    char* get(){ return p; }
    strtype &operator+(strtype &ob);
    strtype &operator=(strtype &ob);
    int operator==(strtype &ob);
    int operator>(strtype &ob);
    int operator<(strtype &ob);
};

strtype::strtype(char* s)
{
    int        l;

    l = strlen(s) + 1;
    p = new char [l];
    if(!p){
        cout << "メモリ割り付けエラー" << endl;
        exit(1);
    }
    len = l;
    strcpy(p, s);
}
strtype::strtype()
{
    int l;

    p = new char [3];
    if(!p){
        cout << "メモリ割り付けエラー" << endl;
        exit(1);
    }
    len = 3; 
}

strtype::~strtype()
{
    delete [] p;
}

strtype &strtype::operator+(strtype &ob)
{
    char *temp;

    temp = new char [len + ob.len];
    strcpy(temp,p);
    strcat(temp,ob.p);
    delete [] p;
    p = new char [len + ob.len];
    if(!p){
        cout << "メモリ割り付けエラー" << endl;
        exit(1);
    }
    len = len + ob.len;    
    strcpy(p,temp);
    delete [] temp;
    return *this;
}

strtype &strtype::operator=(strtype &ob)
{
    if(len < ob.len){
        delete [] p;
        p = new char [ob.len];
        if(!p){
            cout << "メモリ割り付けエラー" << endl;
            exit(1);
        }
    }
    strcpy(p,ob.p);
    return *this;
}

int strtype::operator==(strtype &ob)
{
    return(strcmp(this->p, ob.p) == 0);
}

int strtype::operator>(strtype &ob)
{
    return(strcmp(this->p, ob.p) > 0);
}

int strtype::operator<(strtype &ob)
{
    return(strcmp(this->p, ob.p) < 0);
}

char *show(strtype &ob)
{
    char *s;
    
    s = ob.get();
    return(s);
}

int main()
{
    strtype x1 = "Gundam ", x2 = "RX-78-2";
    strtype x3 = "Guncanon ", x4 = "RX-77";
    strtype x5 = "Guntank ", x6 = "RX-75";
    strtype y1,y2,y3,y4;
    y1 = x1 + x2;
    y4 = y1;
        return (0);

}




この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:演算子オーバーロード後デストラクタでセグメントエラー 29895 Blue 2007/03/09 10:30:27


No.29895

Re:演算子オーバーロード後デストラクタでセグメントエラー
投稿者---Blue(2007/03/09 10:30:27)


(ここはC言語の掲示板なんですけどね。)

とりあえず気になるところ

>strtype::strtype()
>p = new char [3];
pの領域を初期化する必要はないのか?
p[0] = '\0';
を入れておいたほうがよさそう。

>strtype &strtype::operator+(strtype &ob)
> temp = new char [len + ob.len];
tempに対してはメモリ確保チェックしないのですかね?
また、pに対して再度newしていますが、そのままtempを代入すればいいのでは?

>strtype &strtype::operator=(strtype &ob)
> if(len < ob.len){
のときに len を更新していないようですけど。



この投稿にコメントする

削除パスワード

No.29896

Re:演算子オーバーロード後デストラクタでセグメントエラー
投稿者---Blue(2007/03/09 10:45:48)


それと、operator+がどうもoperator+=のように思えます。


この投稿にコメントする

削除パスワード

No.29898

Re:演算子オーバーロード後デストラクタでセグメントエラー
投稿者---Mr.Boo(2007/03/09 11:21:45)


Blueさん、ありがとうございます。
>それと、operator+がどうもoperator+=のように思えます。
むっ、確かに言われてみると、+=の処理になっていますねぇ。
これはシルトさんの本の例題を元に問題を作成したために、こんなになりました。
こちらの意図していることは、文字列を結合して左側のオブジェクトに代入したかったのです。

ご指摘ありがとうございました。



この投稿にコメントする

削除パスワード

No.29899

Re:演算子オーバーロード後デストラクタでセグメントエラー
投稿者---Blue(2007/03/09 11:25:35)


operatorまわりにかんしては
http://www5c.biglobe.ne.jp/~ecb/cpp/04_19_02.html
を参考にしてみてはどうでしょうか?


この投稿にコメントする

削除パスワード

No.29900

Re:演算子オーバーロード後デストラクタでセグメントエラー
投稿者---Mr.Boo(2007/03/09 11:39:24)


Blueさん、ありがとうございます。
>operatorまわりにかんしては
>http://www5c.biglobe.ne.jp/~ecb/cpp/04_19_02.html
>を参考にしてみてはどうでしょうか?
ここは以前私も、C++の勉強の際に利用させていただいておりました。
改めて、見直してみます。

それと、operator+の見直しもしてみたのですが、むしろこちらに原因があるようです。
さらに確認と調査をしてみます。
詳しく解れば、またアップいたします。
有り難う御座いました。


この投稿にコメントする

削除パスワード

No.29897

Re:演算子オーバーロード後デストラクタでセグメントエラー
投稿者---Mr.Boo(2007/03/09 11:14:20)


Blueさん、ありがとうございました。

>(ここはC言語の掲示板なんですけどね。)
以前もここでC++の相談をさせていただいたところ、すごく早く的確な指摘をいただけたもので、
便利に使わせてもらっています。
確かに場違いなのは理解しておりますが、C++の相談先でよいところを知らなかったものですから・・・・。


>とりあえず気になるところ
>
確認した結果、以下の指摘部分を修正すると、現象は発生しなくなりました。
詳細はこれから調査をしていきます。

>>strtype &strtype::operator=(strtype &ob)
>> if(len < ob.len){
>のときに len を更新していないようですけど。
ここは、私も気にはなっていたのですが、配列をnewしたときはdeleteでは特に
取得サイズ指定する必要もないので、特に更新していませんでした。
また、オーバーロード後の処理でも、新しく取得したエリアのサイズを使って
特に処理を行わないので、無視していました。

なお、ここで記載したのは、実際のソフトのうち関係ない部分をすべて削り取って
現象を再現させる最低限の処理のみを残しています。



この投稿にコメントする

削除パスワード

No.29903

Re:演算子オーバーロード後デストラクタでセグメントエラー
投稿者---かずま(2007/03/10 09:14:49)


>> のときに len を更新していないようですけど。
> ここは、私も気にはなっていたのですが、配列をnewしたときはdeleteでは特に
> 取得サイズ指定する必要もないので、特に更新していませんでした。

len を更新しないと、y1 = x1 + x2; で y1.len = 3, y1.p = "Gundam RX-78-2"
となります。y4.len = 3, y4.p = (3バイトの領域) ですから、y4 = y1; で、len が
等しいので新しい領域を確保しなおさず、strcpy() で 3バイトの領域へ
もっと長い文字列をコピーし、領域破壊が起こっています。


> なお、ここで記載したのは、実際のソフトのうち関係ない部分をすべて削り取って
> 現象を再現させる最低限の処理のみを残しています。

それなら、x3, x4, y2, y3 は不要ですね。

他に気になるところは、y1 = y1; のように左辺と右辺が同じオブジェクトの場合、
無駄な strcpy が実行されることでしょうか。

また、operator+ を operator+= ではなく本来の意味で実装しようとすると新しく
作成したオブジェクトを返さないとけいないので、コピーコンストラクタの定義
が必要になります。

一般に operator= を定義したクラスではコピーコンストラクタが必要になる
ことが多いようです。



この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧