web-dev-qa-db-ja.com

検索結果が見つからない場合、「NULL」オブジェクトを返します

私はC++にかなり慣れていないので、学習中は多くのJava主義で設計する傾向があります。とにかく、Javaで、特定のパラメーターに一致する_Collection< T >_からオブジェクトTを返す 'search'メソッドを持つクラスがあれば、そのオブジェクトを返し、オブジェクトがそうでなければコレクションで見つかった場合、nullを返します。次に、呼び出し元の関数でif(tResult != null) { ... }をチェックするだけです

C++では、オブジェクトが存在しないとnull値を返せないことがわかりました。オブジェクトが見つからなかったことを呼び出し元の関数に通知するタイプTの「インジケータ」を返したいだけです。例外をスローしたくないのは、例外的な状況ではないからです。

これは私のコードが今どのように見えるかです:

_class Node {
    Attr& getAttribute(const string& attribute_name) const {
       //search collection
       //if found at i
            return attributes[i];
       //if not found
            return NULL; // what should this be?
    }

private:
    vector<Attr> attributes;
}
_

そのようなマーカーを与えることができるようにどのように変更できますか?

90
aduric

C++では、参照をnullにすることはできません。何も見つからない場合にオプションでnullを返したい場合は、参照ではなくポインタを返す必要があります。

Attr *getAttribute(const string& attribute_name) const {
   //search collection
   //if found at i
        return &attributes[i];
   //if not found
        return nullptr;
}

それ以外の場合、参照で返すことを主張する場合、属性が見つからない場合は例外をスローする必要があります。

(ところで、あなたのメソッドがconstであり、const以外の属性を返すのが少し心配です。哲学的な理由から、const Attr *。この属性も変更する場合は、const以外の属性を返すconst以外のメソッドでオーバーロードできます。)

65
Jesse Beder

ここにはいくつかの可能な答えがあります。存在するかもしれない何かを返したい。ここでは、最も優先度の低いものから最も優先度の高いものまで、いくつかのオプションを示します。

  • 参照によって戻り、例外によって見つけることができないことを通知します。

    Attr& getAttribute(const string& attribute_name) const 
    {
       //search collection
       //if found at i
            return attributes[i];
       //if not found
            throw no_such_attribute_error;
    }

属性が見つからないことは、実行の通常の部分である可能性が高いため、あまり例外ではありません。これの取り扱いはうるさいでしょう。 null参照を持つのは未定義の動作であるため、null値を返すことはできません。

  • ポインターで戻る

    Attr* getAttribute(const string& attribute_name) const 
    {
       //search collection
       //if found at i
            return &attributes[i];
       //if not found
            return nullptr;
    }

GetAttributeの結果がNULL以外のポインターになるかどうかを確認するのを忘れがちであり、バグの簡単な原因です。

  • Boost.Optional を使用します

    boost::optional<Attr&> getAttribute(const string& attribute_name) const 
    {
       //search collection
       //if found at i
            return attributes[i];
       //if not found
            return boost::optional<Attr&>();
    }

Boost :: optionalは、ここで何が起こっているかを正確に示し、そのような属性が見つかったかどうかを検査する簡単な方法を備えています。


サイドノート:std :: optionalは最近C++ 17に投票されたので、これは近い将来「標準的な」ものになるでしょう。

55
Kaz Dragon

NULL戻り値を表す静的オブジェクトを簡単に作成できます。

class Attr;
extern Attr AttrNull;

class Node { 
.... 

Attr& getAttribute(const string& attribute_name) const { 
   //search collection 
   //if found at i 
        return attributes[i]; 
   //if not found 
        return AttrNull; 
} 

bool IsNull(const Attr& test) const {
    return &test == &AttrNull;
}

 private: 
   vector<Attr> attributes; 
};

そしてソースファイルのどこかに:

static Attr AttrNull;
22
Mark Ransom

NULL戻り値が必要な場合は、参照の代わりにポインターを使用する必要があります。

参照自体をNULLにすることはできません。

(将来のコメント投稿者への注意:はい、本当にしようとするなら、参照のアドレスをNULLにすることができます)。

参照とポインタの違いのリストについては、こちらの回答をご覧ください

3
Brian R. Bondy

Java(またはC#)で行った方法では実行できないことがわかったため、別の提案として、オブジェクトの参照を引数として渡して戻ります。 bool値:結果がコレクション内で見つかった場合、渡された参照に結果を割り当てて 'true'を返し、それ以外の場合は 'false'を返します。このコードを検討してください。

typedef std::map<string, Operator> OPERATORS_MAP;

bool OperatorList::tryGetOperator(string token, Operator& op)
{
    bool val = false;

    OPERATORS_MAP::iterator it = m_operators.find(token);
    if (it != m_operators.end())
    {
        op = it->second;
        val = true;
    }
    return val;
}

上記の関数は、キー 'token'に対して演算子を見つける必要があります。見つかった場合は、trueを返し、パラメーターOperator&opに値を割り当てます。

このルーチンの呼び出し元コードは次のようになります

Operator opr;
if (OperatorList::tryGetOperator(strOperator, opr))
{
    //Do something here if true is returned.
}
2
A.B.

ここでNULLを返すことができない理由は、戻り型をAttr&として宣言したためです。末尾の&は、戻り値を「参照」にします。これは基本的に、既存のオブジェクトへのnull以外の保証されたポインターです。 nullを返したい場合は、Attr&Attr*に変更します。

1
JSBձոգչ

関数の戻り値の型はNULLではなくオブジェクトreferenceであるため、pointerを返すことはできません。

0
codaddict