如何检查类中传递的参数是否正确
How to check if passed arguments in a class are correct
假设以下代码:
class myClass{
myClass(int a, int b, int c){};
};
main(){
myClass cl(2,5,6);
}
myClass cl(2,5,6); 将起作用。但是,如果我希望构造函数仅使用特定值怎么办?例如 a>1 b>2 c>1。有没有办法检测错误的参数并在构造函数中"取消"cl的创建?
是的,你可以这样做。你只需要验证构造函数体内的参数。如果它们无效,则抛出异常。
Class Invalid
{
private:
int m_x, m_y;
public :
class MyException : public exception {};
Invalid ( int x, int y )
{
if ( x < 0 || y > 100 )
throw MyException ();
...
}
};
你可以做这样的事情:
myClass(int a, int b, int c)
{
if (a <= 1){
throw something; // ToDo - define `something`, a text string would work.
}
}
等等。请注意重要的一点,如果在构造函数中抛出异常,则不会调用析构函数(尽管将调用任何基类析构函数)。这是内存泄漏的一个常见原因。
在我开始之前,我想澄清一下,这实际上是C++中一个相当大的主题,许多设计模式都是围绕这个问题明确设计的。
一种方法是在构造器中抛出异常:
class myClass {
public:
myClass(int a, int b, int c)
{
if (a<=1 || b <= 2 || c<=1) throw "some exception";
}
};
这通常被认为是一种不好的做法,因为永远不会调用类的析构函数!根据经验,构造函数应该快速而简单。如果构造函数可能失败,则应尝试其他方法。此外,异常处理在C++中是出了名的慢。
所以很多人改用初始化调用:
class myClass {
public:
myClass() { initialized_ = true;}
void initialize((int a, int b, int c) { initialized_ = !(a<=1 || b <= 2 || c<=1);}
bool alive() {return intialized_;}
private:
bool initialized_;
};
然后,当您使用该类时,您可以在初始化尝试后检查对象是否成功。
myClass c;
c.initialize(2,5,6);
我个人不喜欢这样,因为你最终会上僵尸课。
myClass c;
c.initialize(0,0,0);
c.foo();//Legal, compiles, but is WRONG
这个僵尸类采用了 RAII 的想法,老实说,我不应该一直做这个检查。
我首选的处理方法是工厂方法。
class myClass
{
public:
static myClass* makeMyClass(int a, int b, int c)
{
myClass* ret = new myClass();
ret->initialize(a,b,c);
if (!ret->alive()) {delete ret; return null;}
return ret;
}
private:
myClass() { initialized_ = true;}
void initialize((int a, int b, int c) { initialized_ = !(a<=1 || b <= 2 || c<=1);}
bool alive() {return intialized_;}
private:
bool initialized_;
};
(Protip不要使用原始指针,使用智能指针)。
static_assert来实现编译时检查,但也许您必须将调用包装在一个丑陋的宏中,或者可能包含在模板中。
像这样(希望不那么丑陋):
class myClass{
public:
myClass(int a, int b, int c){};
};
#define SafeMyClass(obj, a,b,c) static_assert(a<b,"a<b"); static_assert(b<c,"b<c"); myClass obj(a,b,c);
int main(){
SafeMyClass(cl,2,5,6);
return 0;
}
由于您在程序编写时知道可接受的值范围,因此尝试使用不正确的值构造类意味着您的程序已中断。 您应该使用断言。 断言用于记录类/函数/等的正确用法,并简化调试过程。
http://www.cplusplus.com/reference/cassert/assert/
class myClass{
myClass(int a, int b, int c) {
assert(a > 1 && b > 2 && c > 2);
};
};
assert
将引发异常,如果您传递给它的布尔值计算结果为 false。
通过说assert(a > 1 && b > 2 && c > 2);
你的意思是"程序永远不应该用超出正确范围的a,b和c的值构造myClass"。 如果程序这样做,则程序不正确。 这将使您非常容易找到并更正错误。
如果值来自您无法控制的位置(例如用户输入),则应在 myClass 的构造函数之外验证该输入。 这是适当的关注点分离。
使用 assert
的另一个优点是,当您编译发布/优化构建时,断言的计算结果将为 null 语句。 这样,旨在帮助您调试的代码不会减慢您的发布版本。
记得#include <assert.h>
.
这就是我的做法
class myClass{
public:
myClass(int a, int b, int c):aValue(a), bValue(b), cValue(c){};
private:
int aValue;
int bValue;
int cValue;
};
myClass::myClass(int a, int b, int c){
if(a<2) throw rangeError("the 'a' should be larger than one");
if(b<3) throw rangeError("the 'b' should be larger than one");
if(c<2) throw rangeError("the 'c' should be larger than one");
}
void main(){
try{
myClass cl(2,5,6);
}catch(rangeError re){
cout << re.what() << endl;
}
}
- 在C++中,使用带有 std::optional 参数的函数<T>来表示可选参数是否有意义?
- 如何检查给定的参数是否为 cv::noArray()?
- 如果返回 -1,时间() 的参数是否被修改?
- C++中大多数/所有 setter 函数的参数是否应该写为常量引用?
- 检查两个模板参数是否相同
- 空函数的参数是否加载到缓存中?
- 使用 lambda 作为构造函数参数是否需要C++ 17?
- 了解'this'或其他参数是否为右值
- const-ref传递的模板化参数是否经过优化,以便在足够小时按值传递
- shared_ptr构造函数参数是否应按值传递
- 如何检查模板参数是否为给定值?
- 使用聚合初始化模拟默认函数参数是否存在任何陷阱?
- 在对象序列化期间添加额外参数是否有更好的方法?
- 通过 ssh 发送参数.是否有非阻塞输入函数?
- 如何检查运算符 != 模板参数是否存在 C++ 17?
- 常量引用函数参数:是否可以禁止临时对象?
- 如何检查模板参数是否为 std::variant?
- 是否可以确定函数的参数是否已签名或无符号,以实现可能性超载函数
- 移动 l 值参考参数是否是一种不好的做法?
- 显式指定通用 lambda 的 operator() 模板参数是否合法?