gpt4 book ai didi

const 类型的构造函数初始值设定项的 C++ 正确输入验证

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:18:25 25 4
gpt4 key购买 nike

这真的是验证 C++ 初始化列表和常量成员类型的构造函数输入的正确方法吗?

与其他语言(如 Java/C#)相比,这个通常微不足道的操作是多么冗长,我只是有点吃惊......

class irc_nickname
{
private:
static const std::regex nick_regex_;
const std::string name_;

const std::string & verify_name(const std::string & name)
{
if (!irc_nickname::is_valid(name))
throw std::invalid_argument("The provided name does not conform to irc nickname requirements.");
return name;
}

public:
irc_nickname(const std::string & name) : name_(verify_name(name)) {};

static bool is_valid(const std::string & name)
{
return std::regex_match(name, nick_regex_);
}
};

当然,我不能只在构造函数中执行验证,因为 name_ 是一个 const 类型,并且已经在构造函数中进行了初始化。

如果不是,那么实际的做法是什么?

最佳答案

好的...所以我们有一个“问题”陈述...

taken aback as to how verbose

...以及关于一个选项不可用的断言:

can't just perform the validation in the constructor as name_ is a const type and would already be initialized within the constructor

后者是错误的...您可以分配给数据成员,然后在构造函数中验证它,它简化了代码一点点(尽管在抛出情况下效率稍低) ).只要在构造函数完成之前抛出任何异常,数据成员仍将被正确地“销毁”。

冗长的一个原因是您选择使 is_valid() 成为公共(public)非成员函数,这需要传递参数。您还选择将 verify_name() 放入一个单独的、可重用的函数中,而不是直接在构造函数中执行检查——同样更冗长,但如果它被重用则可能是合理的(例如通过 operator=) 或构造函数可能因太多问题而变得复杂。

将公共(public)成员移到类的顶部(一种广泛遵循的做法,有助于快速掌握面向客户的功能),并且函数先于数据,我们有:

class irc_nickname
{
public:
irc_nickname(const std::string& name) : name_(name) { verify_name(); }

static bool is_valid(const std::string& name)
{
return std::regex_match(name, nick_regex_);
}

private:
void verify_name()
{
if (!is_valid(name_))
throw std::invalid_argument("The provided name does not "
"conform to irc nickname requirements.");
}

static const std::regex nick_regex_;
const std::string name_;
};

如果您真的不需要可重用的 verify_name() - 正如您自己的回答所暗示的那样 - 但确实需要静态公共(public) is_valid(),您最终会与:

class irc_nickname
{
public:
irc_nickname(const std::string& name)
: name_(name)
{
if (!is_valid(name_))
throw std::invalid_argument("The provided name does not "
"conform to irc nickname requirements.");
}

static bool is_valid(const std::string& name)
{
return std::regex_match(name, nick_regex_);
}

private:
static const std::regex nick_regex_;
const std::string name_;
};

您还可以分解出一个可重用的正则表达式验证字符串类,irc_nickname 用于存储 name,从而使 irc_nickname 不那么困惑。

就个人而言,我倾向于使用宏来引发失败的断言:

#define ASSERT_THROW_TYPE(X, TYPE, MSG) \
do { \
if (X) break; \
std::ostringstream oss("ASSERT FAILED !" #X " "); \
oss << __FILE__ << ':' << __LINE__ << ' ' << X; \
throw TYPE(oss.str()); \
} while (false)

#define ASSERT_INVALID_ARG(X, MSG) ASSERT_THROW_TYPE(X, std::invalid_argument, MSG)
#define ASSERT_RUNTIME(X, MSG) ASSERT_THROW_TYPE(X, std::runtime_error, MSG)
...etc...

然后您可以将 if (!is_valid(name_)) throw ... 位减少为更具声明性和信息性:

ASSERT_INVALID_ARG(is_valid(name_), "The provided nickname '" << name_
<< "' does not conform to irc nickname requirements.");

关于const 类型的构造函数初始值设定项的 C++ 正确输入验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30115012/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com