第九回レポート総評




「s2=s1」の後、プログラム終了時にエラーがでる理由

代入演算子が多重定義されていない時に「s2=s1」を実行すると、
資料の図 9 のような状態になります。

この状態でプログラムが終了すると、s1 と s2 に対してそれぞれ デストラクタが呼ばれますが、
それにより 「一度開放した領域を再び開放しようとする」ことになって、 エラーがでます。

なお、 2002 年の 3 月に、linux などで用いられる圧縮ライブラリ zlib の脆弱性が発見されましたが、
これは上記の「メモリの二重開放」に関係しています。

参考:zlib 圧縮ライブラリに脆弱性。Linux ほか多数のプログラムに影響 (ZDNet)
参考:オープンソースソフトの脆弱性が Microsoft 製品にも影響 (ZDNet)


なお、「ひとつのメモリを二つのポインタが指しているから」、「メモリ領域がコピーされていないから」などの解答が多く見られましたが、 これは間違いです。

一つのメモリ領域を複数のポインタが指していても問題ありません。
ただし、メモリを開放するときは、二重に開放しないように注意しなければなりません。

コピーコンストラクタの記述

myString::myString(const myString& x){
  length = strlen(x.s);
  s = new char[length+1];
  strcpy(s, x.s);
}


これは良くできていたようです。

質問:「s1 と s2 が別の領域を指していると確認するにはどうしたら良いか?」

演習時間中に出た質問です。

いま、s1 に "Hello" が格納されているとします。
「s2=s1」を実行したときに、代入演算子により s2 と s1 が別のメモリ領域上の "Hello" を指すようにしました。

このとき、「本当に s1 と s2 が別のメモリを指していることを確認するには どうしたら良いか?」 という質問です。

どうするのが一番分かりやすいかを考えていたので、演習中は中途半端にしか答えられませんでしたが、
以下のようにするのが良いのではないでしょうか。

まず、「myString.h」内部に以下の changeS 関数を作ります。
これは、文字列の i 番目の文字を c に変更するメンバ関数です。

    /*  myString.h 内部 */

    void changeS(int i, char c){
      if(i<length){ 
        s[i] = c;
      }
    }


s1 が "Hello" であるときに「s1.changeS(0,'h');」を実行すると、 s1 の文字列は "hello" に変更されます。
ですから、「s2=s1;」の後に「s1.changeS(0,'h');」を 実行し、s1 と s2 の内容を表示して確かめれば良いでしょう。






C から入る C++ に戻る