我在PC-Lint(au-misra-cpp.lnt)中收到这些错误:
ConverterUtil.cpp(90): 错误864 :(信息 - 涉及变量'transformValue'的表达式 可能取决于评估顺序[ MISRA C ++规则5-2-10 ])
ConverterUtil.cpp(90): 错误864 :(信息 - 涉及变量'transformValue'的表达式 可能取决于评估顺序[ MISRA C ++规则5-2-10 ])
ConverterUtil.cpp(90): 错误534 :(警告 - 忽略功能的返回值 “的std ::变换(标准:: _ String_iterator>>中 的std :: _ String_iterator>>中 std :: _ String_iterator>>,int (*)(int))'(与第998行,文件C:\ Program Files比较 (x86)\ Microsoft Visual Studio 11.0 \ VC \ include \ algorithm)[MISRA C ++ 规则0-1-7和8-4-6],[MISRA C ++规则0-3-2])
关于此代码:
/**Conversion from std::string to bool*/
bool ConverterUtil::ConvertStdStringToBool(const std::string value)
{
std::string transformValue = value;
bool retValue = false;
std::transform(transformValue.begin(), transformValue.end(), transformValue.begin(), &::tolower);
if(transformValue == std::string(static_cast<const char *>("true")))
{
retValue = true;
}
return retValue;
}
我猜测它不喜欢我在转换中使用相同的std :: string作为输入和输出的事实,但使用其他字符串作为输出会产生相同的错误。
是否可以使std :: transform MISRA兼容?
答案 0 :(得分:5)
我只是在这里猜测(如果不能解决你的问题,我可能会删除答案)。
尝试将包含std::transform
的行替换为以下两行:
auto dest = transformValue.begin();
std::transform(transformValue.cbegin(), transformValue.cend(), dest, &::tolower);
请注意使用cbegin()
和cend()
(而不是begin()
和end()
)。
关于另一个话题:当你只做一次时,你正在复制传递给ConvertStdStringToBool
两次的字符串。为此,请替换:
bool ConverterUtil::ConvertStdStringToBool(const std::string value)
{
std::string transformValue = value;
与
bool ConverterUtil::ConvertStdStringToBool(std::string transformValue)
{
(您可能希望在此次更改后将transformValue
重命名为value
。
更新:我的解释为什么我认为这会有所帮助。
首先,请注意transformValue
为非const
。因此,transformValue.begin()
和transformValue.end()
会调用这些重载:
iterator begin(); // non const overload
iterator end(); // non const overload
因此,静态分析器(正确地)得出结论:begin()
和end()
可能会改变transformValue
的状态。在这种情况下,transformValue
的最终状态可能取决于首先调用begin()
和end()
中的哪一个。
现在,当您致电cbegin()
和cend()
时,重载就是:
const_iterator cbegin() const; // notice the const
const_iterator cend() const; // notice the const
在这种情况下,静态分析器不会推断这些调用会改变transformValue
的状态并且不会引发问题。 (严格地说,即使这些方法是const
,它们也可以改变状态,因为类中可能存在mutable
个数据成员,或者方法可能使用邪恶的const_cast
。静态分析器恕我直言不应该因此而受到指责。)
最后评论:电话
std::transform(transformValue.cbegin(), transformValue.cend(), transformValue.cbegin(), &::tolower);
^^^^^^
错了。第三个参数必须是非const
迭代器,也就是说,必须为transformValue.begin()
(只有前两个参数是{{1}方法)。
但是,我想,对于上述类似的推理,仅仅使用c*
作为第三个参数是不够的,这就是为什么我建议创建另一个变量(transformValue.begin()
)。
答案 1 :(得分:2)
这不是一个单独的答案,更像是对Cassio答案的评论,但是评论太长了。
以下是直接使用transformValue.begin()
作为第三个参数实际上很容易失败的原因:在C ++ 03中(不是在11中,但到目前为止GCC尚未切换),std ::的引用计数实现字符串被允许。 libstdc ++有一个。有了这样的版本,value
和transformValue
将共享其内部缓冲区。
现在,当调用transformValue.begin()
时,生成的非const迭代器可以用来修改缓冲区,这会很糟糕,因为它也会改变value
。所以begin()
必须取消共享缓冲区,即仅为transformValue
分配一个唯一的缓冲区。这样做使所有现有的迭代器无效!
因此,在调用cbegin
和cend
的C ++ 98版本中:
const std::string& constValue = transformValue;
std::transform(constValue.begin(), constValue.end(),
transformValue.begin(), &::tolower);
你有一个真正的订单依赖。如果在const调用之前调用非{const}版本的begin()
,那么一切都很好。但是如果首先调用const版本(或end()
),那么新返回的迭代器将被非const调用无效,从而产生未定义的行为。
足够多,代码仍然可能正常工作,因为无效的迭代器将指向旧缓冲区,由value
保持活动状态。因为在大多数情况下发生这种疏散,旧版本将比新版本更长,这是一个非常讨厌的睡眠错误,直到任何一个都不会出现
答案 2 :(得分:0)
虽然迭代器begin()和end()在此调用中是常量,但检查器怀疑调用这些副作用。因此,结果可能会有所不同,具体取决于调用顺序。我有类似的问题,不得不通过使用两个局部变量来关闭检查器来修复它。