1

我想在我的构造函数中抛出一个异常,这样我就不必处理僵尸对象了。但是,我还想预先提供一种验证方法,以便人们可以避免在没有理由的情况下“处理异常”。在 GUI中,预期无效数据并不例外。但是我也想避免代码重复和开销。GCC / Microsoft Visual C++ 编译器是否足够聪明,可以消除两次​​验证输入的低效率,如果没有,是否有一些微妙的变化可以取悦?

说明我的观点的示例代码块如下:

#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++ 编译器是否足够聪明,可以消除两次​​验证输入的低效率,如果没有,是否有一些微妙的变化可以取悦?

您可以将输入封装在一个对象中,该对象会记住验证的结果。

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两种ValidatedInput不同的类型来完成。

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();
    }
};

NonValidatedInput接受未验证的输入,并执行验证,如果验证成功,则可以转换为ValidatedInput对象。如果验证失败,则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才能创建 a 。ValidatedInput

于 2012-06-23T18:33:37.677 回答
0

优化器可能会内联函数 InputIsValid(),但这只是它所能做到的。您还需要将构造函数记录为正在抛出,以及将要抛出的异常类型。就调用该函数的性能成本而言,strcmp() 的成本可以忽略不计。可以说,除非该构造函数在非常紧密的循环中使用,否则成本应该可以忽略不计。

于 2012-06-23T18:25:14.760 回答