C++:如果所有数据可能都已有效,则在构造函数中进行验证是否有开销
C++: Is there an overhead of validating in a constructor if all data may already be valid?
我想在我的构造函数中抛出一个异常,这样我就不必处理僵尸对象。但是,我还想预先提供一种验证方法,以便人们可以避免在没有原因的情况下"处理异常"。在 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;
}
我预计如果单独生成类的目标文件,这可能是不可能的,因为目标文件无法确保人们在调用构造函数之前进行验证,但是当应用程序在单个应用程序中编译并链接在一起时,可以吗?
如果所有数据可能都已有效,则在构造函数中进行验证是否有开销?
是的,如果数据已经过验证,那么您将产生再次验证数据的费用
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
才能创建ValidatedInput
,并且只有在验证成功的情况下。
优化器可以内联函数 InputIsValid(),但这大约是它所能做到的。您还需要将构造函数记录为抛出,以及它将抛出的异常类型。至于调用该函数的性能成本,strcmp()的成本可以忽略不计。可以说,除非该构造函数用于非常紧密的循环中,否则成本应该可以忽略不计。
- "error: no matching function for call to"构造函数错误
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- 选择要调用的构造函数
- 如何委托派生类使用其父构造函数?
- 构造函数正在调用一个使用当前类类型的函数
- 没有用于初始化C++中的变量模板的匹配构造函数
- 初始化具有非默认构造函数的std::数组项的更好方法
- 当从函数参数中的临时值调用复制构造函数时
- 在c++构造函数中使用随机字符串生成器
- 一对向量构造函数:初始值设定项列表与显式构造
- 从构造函数抛出异常时如何克服内存泄漏
- 我不明白为什么我声明一个空的内部结构并将其传递给构造函数
- 继承:构造函数,初始化C++11中基类的类C数组成员
- 具有默认模板类型的默认构造函数的类型推导
- 使用dynamic_cast和构造函数时出错
- C++:如果所有数据可能都已有效,则在构造函数中进行验证是否有开销
- boost::lock_guard分配、构造函数和析构函数开销