メインコンテンツ

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

不適切な値の転送

転送されたオブジェクトが予期せず変更される場合がある

説明

この欠陥は、以下の場合に発生します。

  • std::move を使用して、auto&& 型または T&& 型のオブジェクトを含む、転送参照を関数に転送した場合。

  • std::forward を使用して、rvalue 参照を関数に転送した場合。

以下のコードについて考えます。関数テンプレート callMethod では、パラメーター param1 が転送参照で、パラメーター param2rvalue 参照です。これらのパラメーターを関数 foo() に転送すると、コードで誤って転送参照 param1 に対して std::move が使用され、rvalue 参照 param2 に対して std::forward が使用されます。

#include<string>
#include<iostream>

template <class T> class  bar{};

template<typename T>
void foo(std::string&& s, bar<T>&&){
	//...
} 

template <typename T>
void callMethod(T&& param1, bar<T>&& param2) {
	
	foo(std::move(param1),std::forward<bar<T>&&>(param2));
}
転送参照は T&& または auto&& として宣言され、rvalue 参照は && として宣言されます。転送参照と rvalue 参照を混同すると、不適切な値の転送になります。

Polyspace® は、std::move または std::forward で参照が関数に転送されなかった場合に、この欠陥を報告しません。たとえば、次のコードは、rvalue 参照 b1 と転送参照 b2 を別の関数に転送しません。std::moveb2 とともに使用した場合、または std::forwardb1 とともに使用した場合、欠陥は発生しません。

template <typename T1, typename T2>
void func(T1& b1, T2&& b2)
{
    const T1& b10 = std::forward<B>(b1);
    const T2& b20 = std::forward<B>(b2);
    const T1& b11 = std::move(b1);
    const T2& b21 = std::move(b2);
}

リスク

std::move と転送参照をともに使用すると、lvalue が予期せず変更される可能性があります。std::forwardrvalue 参照をともに使用すると、間違いが生じやすく、コードが複雑になる可能性があります。

修正方法

  • rvalue 参照を関数に転送する場合は、std::move を使用して、参照を rvalue にキャストします。

  • 転送参照またはユニバーサル参照を関数に転送する場合は、オブジェクトが rvalue に制限される場合にのみ、std::forward を使用して参照を rvalue にキャストします。

すべて展開する

#include <cstdint>
#include <string>
#include <utility>


class A
{
public:
    explicit A(std::string&& s)
        : str(std::move(s)) 
    {
    }

private:
    std::string str;
};

template <typename ...T>
void f1(T...t);



template <typename T1, typename T2>
void func(T1&& t1, T2& t2)
{
    f1(std::move(t1));            
    f1(std::forward<T1>(t1));//Suggested fix     

    f1(std::forward<T2>(t2));     
    f1(std::move(t2));//Suggested fix            
}

void func_auto(A& var)
{
    auto&& var1 = var;
    f1(std::move(var1));                    
    f1(std::forward<decltype(var1)>(var1));//Suggested fix 
}

void main()
{
    int32_t i;
    func(0, i);
}

この例では、テンプレート関数 func がパラメーターの t1t2 を関数 f1 に転送します。

  • rvalue 参照 t2std::forward を呼び出すことによって転送されるため、Polyspace は欠陥を報告します。

  • 転送参照 t1std::move を呼び出すことによって転送されるため、Polyspace は欠陥を報告します。t1 が lvalue で初期化される場合は、移動によってパラメーターが予期せず変更される可能性があります。

  • 同様に、Polyspace は、func_auto 内の std::move の使用に対する欠陥を報告します。これは、auto&& 型のオブジェクトが転送参照と見なされるためです。

欠陥ごとに、以下のコード行で推奨修正が示されます。

結果情報

グループ: プログラミング
言語: C++
既定値: 手書きコードはオン、生成コードはオフ
コマンド ライン構文: INCORRECT_VALUE_FORWARDING
影響度: High

バージョン履歴

R2020b で導入