
よろしくお願いします。
クラスのメンバで3つのlongのポインタを宣言し、
コンストラクタ内でそれぞれにnewして領域を確保
しています。
質問1)newを失敗した場合には、そのポインタに
対してdeleteしてはいけないのでしょうか?
質問2)上記3つもエリアの確保のうち、2つめで失 敗した場合、1つ目のdeleteをしてやる
必要はあるのでしょうか?
catch(bad_alloc)でその処理をしようとおもうのですが、そもそもコンストラクタで例外を発生させるなと
かかれている書籍もあるようです。ただ、すでにそういう記載になってしまっており、できれば、いまの構造でメモリーリークを防げないかと思案しております。どなたか、よい方法をご存知の方いらっしゃいましたら、アドバイスいただけましたら幸いでございます。
No.4ベストアンサー
- 回答日時:
#2です。
> たとえば、bのnewでアロケーションを失敗した場合、
> Cのポインタは0で初期化された状態で、deleteしても
> 問題ないのでしょうか?
> また、Bのnewで失敗した状態のBにもdeleteを実行することになりますが、問題ないのでしょうか?
> deleteの順番がポイントなのでしょうか?
#3でも書かれていますが、0, NULLのdeleteは問題ありません。
deleteの順番はこの場合はどうでもいいです。
> また、この場合デストラクタA::~A()は実行されるのでしょうか?
されません。
例えば
A *objA = 0;
try {
objA = new A;
} catch (...) {
}
で例外が発生した場合、newの時点で例外発生->catchブロックへジャンプするので
objAに代入されず、objAは0のままです。
このため、objAのデストラクタを呼ぶことはできません。
したがってコンストラクタで例外が発生する場合は、
例外発生前にコンストラクタ内で確保したりソースを解放してからthrowしなければ
そのリソースを解放する手段がなくなります。
No.5
- 回答日時:
少し出遅れましたが、ひとつずつ回答していきます。
> 質問1)newを失敗した場合には、そのポインタに
> 対してdeleteしてはいけないのでしょうか?
原則としては駄目です。
というのも、newに失敗するとstd::bad_alloc例外が創出されるので、そのポインタには何も代入されず、不定状態になります。あらかじめ空ポインタで初期化しておくか、new(std::nothrow)を使って、失敗時に空ポインタが返るようにしておけば問題ありません。
> 質問2)上記3つもエリアの確保のうち、2つめで失敗した場合、1つ目のdeleteをしてやる
> 必要はあるのでしょうか
必要です。
根本的な問題を指摘するなら、コンストラクタの中で複数のnewを行うべきではありません。どうしてもの場合は、std::auto_ptrなど、スマートポインタを使うか、内部的にcatchして辻褄を合わせる(#2の方の方法)しかありません。
long型の配列を三つ用意するのであれば、std::vector<long>を三つ使う方が得策です。
# std::auto_ptrを使えないのは、new[]を使うからですよね?
No.3
- 回答日時:
#1です。
すいません間違ってました。ISOによるとNULLに対するdeleteは無視されるようです。
よってnewが失敗したポインタをdeleteしても問題ないようです。
No.2
- 回答日時:
自分ならこう書きます。
class A {
private:
A();
~A();
long *a,*b,*c;
};
A::A()
: a(0), b(0), c(0)
{
try {
a = new long;
b = new long;
c = new long;
} catch (...) {
delete c;
delete b;
delete a;
throw; //同じ例外をthrow
}
}
A::~A()
{
delete c;
delete b;
delete a;
}
コンストラクタで例外を投げないようにするには、
クラスAは初期化が完全に成功したかを示すフラグメンバ変数を持ち
コンストラクタで例外が起こらなかった場合そのメンバをtrueに設定する。
以降メンバ変数にアクセスする全ての関数の冒頭で
初期化が完全に終わっているかチェックする。
となり、変更箇所が多いためお勧めしません。
この回答への補足
この方法ですと現在のソースの修正がしやすいので、
もう少し教えていただきたいのですが、
たとえば、bのnewでアロケーションを失敗した場合、
Cのポインタは0で初期化された状態で、deleteしても
問題ないのでしょうか?
また、Bのnewで失敗した状態のBにもdeleteを実行することになりますが、問題ないのでしょうか?
deleteの順番がポイントなのでしょうか?
また、この場合デストラクタA::~A()は実行されるのでしょうか?
コンストラクタで例外を投げる方向で設計をしようと思います。よろしくお願いいたします。
No.1
- 回答日時:
>質問1)newを失敗した場合には、そのポインタに対してdeleteしてはいけないのでしょうか?
駄目です。newが失敗したポインタにはNULLが入っています。
>質問2)上記3つもエリアの確保のうち、2つめで失敗した場合、1つ目のdeleteをしてやる必要はあるのでしょうか?
1つ目のdeleteをしてやる必要があります。(解放しないと1つ目のメモリが確保されたままになります。)
std::auto_ptrを使ってはどうでしょうか?
http://www.doumo.jp/postgretips/tips.jsp?tips=78
ありがとうございました。
std::auto_ptrが使えればよかったのですが、
移植性を考えて作る必要があり今回は使用しない
方向で設計をせざるを得なくなりました。
勉強になりました。ありがとうございます。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C言語のポインタに直接アドレス...
-
コンストラクタでnewを失敗した...
-
セグメントエラー
-
init関数の意味
-
ExcelVBAでのkernel32(64bit)
-
お絵かきソフトにUNDO、REDOを...
-
Run-Time Check Failure #3とい...
-
【C言語】戻り値が構造体の関数
-
CImage GetBitsメソッドについて
-
基本アルゴリズムの『返す』の...
-
単方向リスト
-
NULLとブランクの違い
-
メモリのアドレスからの値の取...
-
ポインタについて
-
LPSTR型の初期化について
-
fopne で失敗する原因
-
無効なポインタ操作のエラー
-
ハンドルはポインタか
-
void*にキャストするのがナンセ...
-
関数から配列を返すには?
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C言語のポインタに直接アドレス...
-
init関数の意味
-
セグメントエラー
-
Run-Time Check Failure #3とい...
-
ExcelVBAでのkernel32(64bit)
-
戻り値で構造体を返すことは可...
-
fopne で失敗する原因
-
参照型で受け取った引数をポイ...
-
トリプルポインタが必須!とな...
-
ハンドルはポインタか
-
LPSTR型の初期化について
-
ポインターの使用法や利点
-
ポインタについて
-
c言語で任意のファイルから読み...
-
基本アルゴリズムの『返す』の...
-
コンストラクタでnewを失敗した...
-
ハンドル、アドレス、ポインタ...
-
アプリを32bitから64bit移行
-
デバイスハンドルとは?
-
NULLとブランクの違い
おすすめ情報