簡體   English   中英

如何在不違反MISRA C ++ 2008咨詢規則5-2-10的情況下使用std :: transform?

[英]How to use std::transform without violating MISRA C++ 2008 Advisory Rule 5-2-10?

我在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 :: transform(std :: _ St​​ring_iterator >>,std :: _ St​​ring_iterator >>,std :: _ St​​ring_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兼容?

我只是在這里猜測(如果不能解決您的問題,我可能會刪除答案)。

嘗試用以下兩個替換包含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()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() (只有前兩個參數是c*方法)。

但是,我想,由於上述類似的原因,僅使用transformValue.begin()作為第三個參數是不夠的,這就是為什么我建議創建另一個變量( dest )。

這不是一個單獨的答案,更像是對Cassio答案的評論,但是評論太長了。

這是直接將transformValue.begin()作為第三個參數實際上很容易失敗的方式:在C ++ 03中(不是在11中,但到目前為止GCC尚未切換),允許引用計數的std :: string實現。 libstdc ++有一個。 使用這樣的版本, valuetransformValue將共享它們的內部緩沖區。

現在,當調用transformValue.begin()時,可以使用生成的非常量迭代器來修改緩沖區,這很不好,因為它也會更改value 因此begin()必須取消共享緩沖區,即僅為transformValue分配唯一的緩沖區。 這樣做會使所有現有的迭代器無效

因此,在調用的C ++ 98版本cbegincend

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

你有一個真實的訂單依賴性。 如果begin()的非const版本在const調用之前被調用,則一切都很好。 但是,如果首先調用const版本(或end() ),則新返回的迭代器將通過非const調用而無效,從而產生未定義的行為。

足夠令人討厭的是,該代碼可能仍然可以工作,因為無效的迭代器將指向舊緩沖區,該緩沖區通過value保持活動。 由於在大多數情況下會發生這種不共享的情況,因此舊副本的時間將比新副本的時間長,這是一個令人討厭的沉睡者錯誤,直到其中任何一個都不會出現

  • 舊副本可能在操作過程中消失,例如,因為舊副本已經消失了,但是另一個副本存在於另一個線程上,並且隨時可能消失,或者
  • 代碼的更改方式希望通過非const迭代器進行的更改將反映在const迭代器中(指向不同的緩沖區,因此看不到它們)。

盡管迭代器begin()和end()在此調用中是恆定的,但檢查器懷疑調用它們會帶來副作用。 因此,根據調用順序,結果可能會有所不同。 我有一個類似的問題,必須通過使用兩個局部變量來關閉檢查器來解決。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM