2010-11-11 94 views
1

我遇到了一个令人讨厌的问题,我写了一个C++函数,其目的是验证用户输入。该函数读取用户输入,验证它是否是数字,如果是,它是否在范围[min,max]中。将字符串错误的类型转换为unsigned int

当我使用无符号类型调用模板函数(如size_t),并且输入是负数时,会发生此问题。字符串流将字符串转换为类似于4294967291的字符串。我可以看到程序正在将数据转换为接近无符号数据类型的最大值(在numeric_limits标头中定义)的值,但我的问题是为什么,因为if语句应该停在sstream >> value

我的代码:

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

谢谢您的时间!

+0

不要传递它一个无符号类型? – Mud 2010-11-11 04:38:38

回答

2

在C++算术涉及一个unsigned类型与Ñ值的比特,是保证将模2^Ñ。这意味着通过添加或减去2的合适倍数,将任何结果回卷到0到2的范围内。这也是在C.

所以你需要检查减号输入,或添加一些其他检查。

顺便说一下,您的if>>&&对我的坏码表产生了一些影响。我永远不会记得>>&&的运算符优先级。我想如果它编译它一定是好的,但是,因为>>不能取右值。检查...好的,但我会用圆括号来说明这一点。

此外,在代码结构上,将交互输入与输入检查分开是一个好主意。例如,您可以在GUI程序中使用任何代码,并使用编辑字段的输入?不,不是因为它是...

干杯&心连心,

+1

感谢您的理论解释。它帮助我理解这个问题。增加了减号检查,它可以很好地工作:'if(input [0] ==' - '&& std :: numeric_limits :: min()== 0)'。关于坏码,你完全正确,因此我也解决了这个问题:'if((sstream >> value)&&(value> = min)&&(value <= max))'。事实上,它更具可读性,并且没有任何疑问。 – 2010-11-11 05:11:33

+0

最后,至少在代码结构上,我认为解决方案将把函数分成两部分,一部分用户输入,另一部分用于验证。我只有一个怀疑。我应该将try和catch块留在getter中,还是完全处理validator中的异常? – 2010-11-11 05:11:54

+0

@renatorodrigues:保留你拥有的函数的合约是很自然的,并且包括它对异常的回应。我设想了更多的重构,比如将getline后面的代码移动到第一个catch,并将其移动到一个单独的函数中,该函数接受一个字符串并产生一个数字(或者在不能时抛出)。干杯, – 2010-11-11 06:10:21

1

阿尔夫已经回答了这一点,但我有一对夫妇的其他的想法。 拉取从try块中取出输入的代码。你没有捕捉它可能抛出的任何异常,所以它也没有传达这个意图。 try块应该在if(input.empty())之前开始... 然后将try块中的所有东西放到一个validate函数中。这清理了代码。但是,对于在GUI中的使用,您希望创建一个只需获取输入而不进行验证并显示验证功能的函数。然后用户可以根据需要处理验证异常。尽管在这种情况下,我并没有看到使用异常而不是简单的错误代码进行验证的好处。

希望这会有所帮助,

+0

嗯,它确实有帮助。谢谢! – 2010-11-11 12:19:06

相关问题