2013-08-09 5 views
1

я получаю эти ошибки в PC-Lint (аи-Мишра-cpp.lnt):Как использовать std :: transform без нарушения MISRA C++ 2008 Консультативное правило 5-2-10?

ConverterUtil.cpp (90): ошибка 864: (Info - выражение с переменной 'transformValue' зависит, возможно о порядке оценки [MISRA C++ Правило 5-2-10])

ConverterUtil.cpp (90): ошибка 864: (Info - выражение с переменной 'transformValue' возможно, зависит от порядка оценки [ MISRA C++ Правило 5-2-10])

ConverterUtil.cpp (90): ошибка 534 (Внимание: - Не обращая внимания на возвращаемое значение функции «станд :: преобразование (станд :: _ String_iterator >>, станд :: _ String_iterator >>, станд :: _ 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

Несвязанный, но поскольку вы передаете значение 'value' в свою функцию, локаль' tranformValue' не используется. У вас уже есть временная копия в 'value'. Вы можете отказаться от 'const' в параметре и использовать' value' в своем коде вместо 'tranformValue' (хотя я бы сохранил его как-есть, но сделав параметр const-ref). – WhozCraig

+0

Возможно, он хочет, чтобы вы скопировали итераторы 'begin()' и 'end() и передали копии в' std :: transform'. – juanchopanza

+1

Если вы хотите нечувствительность к регистру, посмотрите здесь много ответов http://stackoverflow.com/questions/11635/case-insensitive-string-comparison-in-c –

ответ

5

Я просто угадываю здесь (и я, вероятно, удалю ответ, если он не решит вашу проблему).

Попробуйте заменить строку containning 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); 
                       ^^^^^^ 

неправ. Третий аргумент должен быть инетером non const, то есть должен быть transformValue.begin() (только первые два аргумента - методы c*).

Однако, я думаю, для аналогичных рассуждений, как указано выше, просто используя transformValue.begin(), поскольку третьего аргумента будет недостаточно, и поэтому я предложил создать другую переменную (dest).

+0

Какая разница между использованием begin() end() и cbegin() и cbegin() cend()? Потому что это все, что нужно, чтобы сделать его счастливым: std :: transform (transformValue.cbegin(), transformValue.cend(), transformValue.cbegin(), & :: tolower); – MathiasWestin

+0

@MathiasWestin: Я выложу сообщение об обновлении. –

+0

@MathiasWestin 'cbegin()' возвращает 'const_iterator'. Честно говоря, я шокирован вашим выходным итератором, поскольку const-iterator даже * компилирует *. Вы уверены, что это не просто 'begin()' в вашем коде (третий параметр)? – WhozCraig

2

Это не отдельный ответ, скорее как комментарий к ответу Кассио, но слишком длинный комментарий.

Вот как напрямую можно использовать transformValue.begin(), так как третий параметр может действительно сбой: в C++ 03 (не в 11, но GCC до сих пор не переключился) была реализована реализация std :: string с подсчетом ссылок , У libstdC++ есть один. С такой версией value и transformValue разделили бы свой внутренний буфер.

Теперь, когда вызывается transformValue.begin(), результирующий не-константный итератор может быть использован для изменения буфера, что было бы плохо, потому что оно также изменило бы значение value. Таким образом, begin() должен разобрать буфер, т. Е. Выделить уникальный буфер только для transformValue. Выполнение этого аннулирует все существующие итераторы!

Таким образом, в версии на C++ 98 вызова cbegin и cend:

const std::string& constValue = transformValue; 
std::transform(constValue.begin(), constValue.end(), 
       transformValue.begin(), &::tolower); 

у вас есть зависимость реального порядка. Если неконстантная версия begin() вызывается перед вызовами const, все в порядке. Но если сначала вызывается версия const (или end()), вновь возвращенные итераторы будут аннулированы неконстантным вызовом, что приведет к неопределенному поведению.

Наверное, код, вероятно, будет работать, потому что недействительные итераторы будут указывать на старый буфер, который сохраняется в памяти value.Так как в большинстве случаев, когда такой закрыть доступ случается, старая копия будет дольше, чем новая копия, это очень неприятная шпала ошибка, которая не будет поверхность, пока либо

  • старая копия не может исчезнуть во время операции, например потому что старая копия уже ушла, но другая копия существует в другом потоке и может исчезнуть в любой момент, или
  • код изменен таким образом, который ожидает, что изменения, сделанные через неконстантный итератор, будут отражены в константе итераторы (которые указывают на другой буфер и, следовательно, не будут их видеть).
0

Хотя итератор begin() и end() являются постоянными в этом вызове, контролер подозревает побочные эффекты при их вызове. Таким образом, результат может быть быть различным в зависимости от последовательности вызовов. У меня была аналогичная проблема, и мне пришлось исправить ее, используя две локальные переменные, чтобы заткнуть контрольную панель.