[英]Detecting negative number
我有一个代码,其中用户必须传递> 0数字否则此代码将抛出。 使用此arg的类型作为std :: size_t不起作用,因为负数给出大的正数。 如果我使用签名类型或是否有其他方法来强制执行它,这是好的做法吗?
void f(std::size_t number)
{
//if -1 is passed I'm (for obvious reason) get large positive number
}
我认为这个问题没有明确的正确答案。 你可以看看Scott Meyers关于这个主题的意见:
一个问题是无符号类型往往会降低检测常见编程错误的能力。 另一个原因是它们通常会增加类的客户端错误地使用类的可能性。
最后,要问的问题是:您是否需要无符号类型提供的额外可能值?
很大程度上取决于您想象客户想要传递的论点类型。 如果他们正在传递int,并且这显然足以容纳您将要使用的值范围,那么使用std :: size_t没有实际优势 - 它不会强制执行任何操作,以及问题的显示方式因为一个显然庞大的数字更令人困惑。
但是 - 最好使用size_t,因为它有助于记录API的期望。
你显然不能对运行时生成的值进行“> 0”的编译时检查,但至少可以消除有意义的巨大数字的负输入ala
template <typename T>
void f(T t)
{
if (!(t > 0))
throw std::runtime_error("be positive!");
// do stuff with t, knowing it's not -1 shoehorned into size_t...
...
}
但是,如果你真的关心这个,你可以提供重载:
// call me please e.g. f(size_t(10));
void f(size_t);
// unimplemented (and private if possible)...
// "want to make sure you realise this is unsigned: call f(size_t) explicitly
void f(int32_t);
void f(int64_t);
...然后有一个编译时错误导致注释重新调用者显式提供size_t参数(必要时进行转换)。 强制客户端提供size_t类型的arg是一种很好的方法,可以确保他们意识到这个问题。
Rin也有一个好主意 - 它可以在它工作的地方工作得很好(取决于有一个大于size_t的signed int类型)。 去看看吧....
编辑 - 以上模板构思的演示......
#include <iostream>
template <typename T>
void f(T t)
{
if (!(t > 0))
std::cout << "bad call f(" << (int)t << ")\n";
else
std::cout << "good f(" << (int)t << ")\n";
}
int main()
{
f((char)-1);
f((unsigned char)255);
}
我遇到了同样的问题: 将字符串类型转换为unsigned int
因为在我的情况下,我得到了用户的输入,我的方法是将数据作为字符串读取并检查其内容。
template <class T>
T getNumberInput(std::string prompt, T min, T max) {
std::string input;
T value;
while (true) {
try {
std::cout << prompt;
std::cin.clear();
std::getline(std::cin, input);
std::stringstream sstream(input);
if (input.empty()) {
throw EmptyInput<std::string>(input);
} else if (input[0] == '-' && std::numeric_limits<T>::min() == 0) {
throw InvalidInput<std::string>(input);
} else if ((sstream >> value) && (value >= min) && (value <= max)) {
std::cout << std::endl;
return value;
} else {
throw InvalidInput<std::string>(input);
}
} catch (EmptyInput<std::string> & emptyInput) {
std::cout << "O campo não pode ser vazio!\n" << std::endl;
} catch (InvalidInput<std::string> & invalidInput){
std::cout << "Tipo de dados invãlido!\n" << std::endl;
}
}
}
也许你应该将read-function包装到另一个函数中,该函数的目的是获取int
并验证它。
编辑:Ok int
只是第一个想法,所以读取和解析string
Fisrt解决方案
void f(std::ptrdiff_t number) {
if (number < 0) throw;
}
二解决方案
void f(std::size_t number) {
if (number > std::numeric_limits<std::size_t>::max()/2) throw;
}
这是你不能做太多事情的情况之一。 编译器通常在将签名转换为无符号数据类型时发出警告,因此您必须信任调用者注意该警告。
您可以使用按位运算来测试它,例如:
void f(std::size_t number)
{
if(number & (0x1L << (sizeof(std::size_t) * 8 - 1)) != 0)
{
// high bit is set. either someone passed in a negative value,
// or a very large size that we'll assume is invalid.
// error case goes here
}
else
{
// valid value
}
}
此代码假定为8位字节。 =)
是的,大值会失败,但你可以记录它们是不被允许的,如果你真的需要防止它。
谁在使用此API? 我建议他们修复代码,而不是使用这样的解决方案。 =)我认为“正常”的最佳做法是让调用者使用size_t,如果他们试图将签名值放入其中,他们的编译器会大声抱怨。
我不得不考虑一下这个问题,这就是我要做的。
如果您的函数负责在传递负数时抛出异常,那么函数的签名应该接受有符号整数。 那是因为如果你接受一个无符号数字,你将永远无法明确告诉一个数字是否为负数而你将无法抛出异常。 IOW,你想投诉你的抛出异常的任务。
您应该确定什么是可接受的输入范围,并使用足够大的有符号整数来完全包含该范围。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.