1

ゾンビオブジェクトを処理する必要がないように、コンストラクターで例外をスローしたいと思います。しかし、私はまた、人々が理由のない「例外を扱う」ことを避けることができるように、事前に検証方法を提供したいと思います。GUIでは、無効なデータを予期することも例外ではありません。ただし、コードの重複やオーバーヘッドも避けたいと思います。GCC / Microsoft Visual C ++コンパイラは、入力を2回検証するというこの非効率性を取り除くのに十分スマートですか?そうでない場合は、微妙な変更がありますか?

私のポイントを示すサンプルコードブ​​ロックは以下のとおりです。

#include <string>
#include <exception>
#include <iostream>

using std::string;
using std::cout;
using std::endl;
using std::exception;


// a validation function
bool InputIsValid(const string& input) {
    return (input == "hello");
}

// a class that uses the validation code in a constructor
class MyObject {
    public:

    MyObject(string input) {
        if (!InputIsValid(input))    //since all instances of input
            throw exception();       //has already been validated
                                     //does this code incur an overhead
                                     //or get optimised out?

        cout << input << endl;       
    };

};

int main() {

    const string valid = "hello";

    if (InputIsValid(valid)) {
        MyObject obj_one(valid);
        MyObject obj_two(valid);
    }

    return 0;
}

クラスのオブジェクトファイルが単独で生成された場合、コンストラクターを呼び出す前にユーザーが検証することを保証する方法がないため、これはおそらくあり得ないと思いますが、アプリケーションがコンパイルされ、単一のアプリケーションにリンクされている場合はそうですか?可能ですか?

4

2 に答える 2

5

すべてのデータがすでに有効である可能性がある場合、コンストラクターで検証するオーバーヘッドはありますか?

はい、データがすでに検証されている場合は、データを再度検証するためのコストが発生します

GCC / Microsoft Visual C ++コンパイラは、入力を2回検証するというこの非効率性を取り除くのに十分スマートですか?そうでない場合は、微妙な変更がありますか?

入力をオブジェクトにカプセル化すると、そのオブジェクトは検証の結果を記憶します。

template <typename INPUT_TYPE>
class InputObject {
    INPUT_TYPE input_;
    bool valid_;
public:
    typedef <typename VALIDATE>
    InputObject (INPUT_TYPE in, VALIDATE v) : input(in), valid_(v(in)) {}
    const INPUT_TYPE & input () const { return input_; }
    bool isValid () const { return valid_; }
};

typedef InputObject<std::string> MyInput;

class MyObject {
public:
    MyObject (const MyInput &input) {
        if (!input.isValid()) throw exception();
        //...
    }
};

InputObjectバリデーター関数を呼び出し、検証結果をフラグに格納するコンストラクター。次にMyObject、フラグをチェックするだけで、検証を再度実行する必要はありません。

int main () {
    MyInput input("hello", InputIsValid);

    try {
        MyObject obj_one(input);
        MyObject obj_two(input);
    }
    catch (...) {
        //...
    }
}

DeadMGが示唆しているようにMyObject、検証済みの入力のみを受け入れるように要求することで、より強力な型チェックを実現できます。throwそうすれば、コンストラクターに入れる必要はまったくありません。NonValidatedInputこのようなスキームは、ValidatedInput2つの異なるタイプを作成することで実現できます。

template <typename> class NonValidatedInput;

template <typename T>
class ValidatedInput {
    friend class NonValidatedInput<T>;
    T input;
    ValidatedInput (const T &in) : input(in) {}
public:
    operator const T & () const { return input; };
};

template <typename T>
class NonValidatedInput {
    T input;
public:
    operator ValidatedInput<T> () const { return ValidatedInput<T>(input); }
    template <typename V>
    NonValidatedInput (const T &in, V v) : input(in) {
        if (v(input) == false) throw exception();
    }
};

NonValidatedInputValidatedInput検証されていない入力を受け入れ、検証を実行し、検証が成功した場合はオブジェクトに変換できます。検証が失敗した場合、NonValidatedInput例外をスローします。したがって、MyObjectコンストラクターはを受け入れるだけなので、検証をチェックする必要はまったくありませんValidatedInput

typedef ValidatedInput<std::string> MyInput;

class MyObject {
public:
    MyObject (MyInput input) {
        std::string v = input;
        std::cout << v << std::endl;
    }
};

int main () {
    try {
        MyInput input = NonValidatedInput<std::string>("hello", InputIsValid);
        MyObject obj_one(input);
        MyObject obj_two(input);
    }
    catch (...) {
        //...
    }
}

ここでの型安全性は非常に強力です。これは、検証が成功した場合にのみ、NonValidatedInputを作成できるためです。ValidatedInput

于 2012-06-23T18:33:37.677 に答える
0

オプティマイザーは関数InputIsValid()をインライン化する場合がありますが、それはほぼその範囲内です。また、コンストラクターをスローするように文書化する必要がありますが、スローする例外のタイプは例外です。その関数を呼び出すためのパフォーマンスコストに関しては、strcmp()のコストはごくわずかです。ただし、そのコンストラクターが非常にタイトなループで使用されていない限り、コストはごくわずかであると言えば十分です。

于 2012-06-23T18:25:14.760 に答える