3

失敗したときに null オブジェクトを作成するコンストラクター (c++) を作成するにはどうすればよいですか。

DCMTK ライブラリDicomImageのクラスのように動作するクラスを作成したいと考えています。

#include "diregist.h"   /* required to support color images */
DicomImage *image = new DicomImage("test.dcm");

if (image != NULL)
{
    if (image->getStatus() == EIS_Normal)
    {
        Uint8 *pixelData = (Uint8 *)(image->getOutputData(8 /* bits per sample */));

        if (pixelData != NULL)
        {
            /* do something useful with the pixel data */
        }
    } 
    else
        cerr << "Error: cannot load DICOM image (" << DicomImage::getString(image->getStatus()) << ")" << endl;
}
delete image;
4

6 に答える 6

2

簡単ではありません。DicomImage::operator new()DicomImage クラスの宣言内でオーバーライドできます。次に、失敗して NULL を返す可能性のある実際のロジックは、実際のコンストラクターではなく、オペレーター new() 本体に入ります。コンストラクター内に入ると、NULL を返すには遅すぎます。その時点で、オブジェクトは既に作成されています。問題は、オペレーター new() がコンストラクターのパラメーターを受け取らないため、失敗するために必要な情報がない可能性があることです。

もう 1 つの方法は、ファクトリ メソッドまたはファクトリ クラスで実際にインスタンスを作成することです。コードは次のようになります。

DicomImage* pImage = CreateDicomImage( "stuff" );

ただし、あなたの質問には「例外処理」が含まれていたため...そして、少なくとも答えをプログラマーSE(スタックオーバーフローとは対照的に)の質問にもう少し適したものにするために、私はあなたができることとすべきであることを指摘したいと思いますC++ の例外処理を利用します。

NULL を返すと、new DicomImage() の呼び出しの直後にすべてのクライアント コードにエラー チェック ロジックを振りかけるように強制されます。これは、エラー チェックが実際のアプリケーション ロジックと混ざり合う傾向があるため、可読性が損なわれます。

次のようなコードを作成したほうがよいと思いませんか。

std::unique_ptr< DicomImage > pImage( new DicomImage( "stuff" ) );
pImage->DoSomeCommand();
pImage->DoSomeOtherCommand();

...そして、作成が失敗した場合の「what-if」条件について心配する必要はありません。これは、C++ 例外処理を使用し、作成が失敗した場合にコンストラクターが例外をスローするようにすることで実現できます。このようなものを処理するコードのチャンクの周りに try-catch ブロックをセットアップし、その try ブロック内にあるのは純粋なアプリケーション ロジックです。コードを汚染するエラー チェックはなく、イメージの作成に失敗してもクラッシュしません。

...そして、スマート ポインターを使用することで、後で失敗した場合に pImage が常に削除されることも保証されます。そのため、関数を終了する前に delete を呼び出さなければならないことを心配する必要はありません。

于 2012-05-18T23:35:19.420 に答える
1

DicomImage を使用するコードは、あなたが思っていることをしません。

サンプルコード

if (image != NULL)
{

システムがメモリ不足の場合に NULL を返す、例外のない環境向けの防御的なプログラミングです。

例外を有効にすると、new はメモリ不足の例外をスローします。例外が無効になっている場合、new は NULL を返します。

あなたの質問に答えるために、コンストラクターは NULL を返すことはできません。

ただし、静的ファクトリ メソッドは NULL を返すことができます。

class Foo
{
public:
    static Foo* MakeFoo()
    {
       Foo* foo = NULL;
       if (LifeIsGood())
           foo = new Foo();
       return foo;
    }
private:
    Foo();
};

Foo* myFoo = Foo::MakeFoo();
if (myFoo)
    BeFooish(myFoo);
于 2012-05-19T00:03:02.237 に答える
0

new() 演算子を使用してこれを行うことは、実際には new() 演算子をオーバーライドする目的ではありません。あなたの例から、クライアントコードの変更を許可しているかどうかわかりません。ただし、クライアント コードを制御できる場合は、代わりにコンストラクターを使用するファクトリ メソッドを使用します。

class Foo {

  Foo(int arg) {...}

  static Foo *new_Foo(int arg) {
    if (! I_like(arg)) return null;
    return new Foo(arg);
  }

}

// ...
// in the client

Foo *foo =
// nope:
// new Foo(3);
// do this instead:
Foo.new_Foo(3);
于 2012-05-19T07:08:56.150 に答える
0

コンストラクターがこれを行うことができるとは思わない - この URL は、コンストラクターが null を返せないことを示しています

http://social.msdn.microsoft.com/forums/en-US/csharplanguage/thread/1450ed84-277f-46d3-b2ea-8352986f877c

おそらく「ハック」があるかもしれませんが、おそらく合法ではありません おそらくすでにこれらすべてを知っているでしょうが、念のため: (1) コンストラクターは値を返すことができず、(2) コンストラクターには何も制御できないと思いますコンストラクターを呼び出したインスタンスに割り当てられたメモリを超えますが、コンストラクターはクラス メンバーを NULL 値に設定できます。

この URL には回避策があります - 本当に NULL (推奨されません) を使用する必要がある場合は、コンストラクターを非公開にし、「ファクトリ メソッド」(関数) を使用します。

コンストラクターは NULL 値を返すことができますか?

これはあなたの質問とは別のものであることは知っていますが、新しいものに関するコンパイラの動作を誰かが認識していることを確認したかっただけです:

この URL によると、最新のコンパイラは new 演算子で NULL を返すことは想定されていません (代わりに例外をスローすることが想定されています) が、古いコンパイラは許可されています。

http://www.parashift.com/c++-faq-lite/new/new-never-returns-null.html

于 2012-05-18T23:44:28.690 に答える
0

のドキュメントから判断すると、DicomImageそのクラスのインターフェイスをエミュレートする必要はありません。

于 2012-05-19T03:44:10.083 に答える
0

オブジェクトの作成で null を返すことはできませんが、演算子 == および!= の動作を変更することはできます。次のコードを試してください。試したことはありません。

bool MyClass::operator==(const MyClass &other) const {
    if(&other == null){
        if(/* your validations */){
            return true;//it is null
        }else{
            return false;//
        }       
    }
    return (*this == other);//it is not compare with null
}
bool MyClass::operator!=(const MyClass &other) const {
    if(&other == null){
        if(/* your validations*/){
            return true;//is not null
        }else{
            return false;
        }       
    }
    return !(*this == other);//it is not compare with null
}
于 2012-05-20T03:27:51.703 に答える