このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。
計算量の多い値渡し
パラメーターのコピーの計算量が多くなる場合がある
説明
この欠陥は、パラメーターを参照やポインターではなく値で渡すが、パラメーターが変更されておらず、以下のどちらかの場合に発生します。
パラメーターが非トリビアル コピー可能な型である。非トリビアル コピー可能な型の詳細については、is_trivially_copyable を参照してください。
パラメーターが特定のサイズを上回るトリビアル コピー可能な型である。たとえば、
2 * sizeof(void *)
を上回るオブジェクトは、参照渡しやポインター渡しより値渡しの方が計算量は多くなります。
Polyspace® は、パラメーターが const
に宣言されていなくても、前述の条件を満たしている変更されていないパラメーターにフラグを設定します。
Polyspaceは、以下の場合に欠陥を発生させません。
値渡しのパラメーターが移動のみの型である。たとえば、
std::unique_ptr
は、移動元にできますが、コピーすることはできません。値渡しのパラメーターが変更された。
パラメーターが、派生クラスのオーバーライド元のメソッド
virtual
に値渡しされる。この場合、この欠陥を修正するには基底クラス メソッドのシグネチャの変更が必要となることがありますが、派生クラスのオーナーはこの変更を実行できない可能性があります。
パラメーターが基底クラスの
virtual
メソッドに値渡しされ、パラメーターは非const
であった。この場合、派生クラスにそのパラメーターを変更するオーバーライド元のメソッドがあり、基底クラスのメソッドに修正が適用された場合に、オーバーライド元のメソッドが正しく更新されない可能性があります。
パラメーターが
const
の場合は、派生クラスのオーバーライド元のメソッドはパラメーターを変更しないため、基底クラスで修正を適用しても問題ありません。この場合、Polyspace は [計算量の多い値渡し] 欠陥を報告します。
たとえば、次のコードでは Polyspace は、以下の関数とメソッドの欠陥を報告しません。
関数
offset()
(パラメーターが変更されるため)。関数
moveOnly()
(パラメーターが移動のみの型であるため)。メソッド
D::parse_M
およびD::print_M
(派生クラスのオーバーライド元のメソッドvirtual
であるため)。メソッド
Base::print_M
(非const
パラメーターがある基底クラスのvirtual
メソッドであるため)。
Polyspace は Base::parse_M
について欠陥を報告します。これは、そのパラメーターが const
であり、非トリビアル コピー可能であるためです。
#include <string>
#include <memory>
#include <iostream>
typedef struct Buffer
{
unsigned char bytes[20];
int index;
} Buffer;
void offset(Buffer modifiedBuffer)
{
++modifiedBuffer.index;
}
void moveOnly(std::unique_ptr<Buffer> move_only_param);
// virtual methods example
class Base
{
public:
virtual void parse_M(const std::string msg);
virtual void print_M(std::string msg)
{
std::cout << "Base message: " << msg << "\n";
}
};
class D : public Base
{
public:
void parse_M(const std::string msg) override;
void print_M(std::string msg) override
{
std::cout << "Derived message: " << msg << "\n";
}
};
リスク
パラメーターを値で渡すと、パラメーターのコピーが作成されますが、パラメーターのコピーの計算量が多い場合は非効率になります。参照またはポインターで渡すつもりでも、関数シグネチャに const&
または const*
を入れ忘れて、非効率なバージョンの関数を実行する可能性があります。
修正方法
C コードの場合はパラメーターを const
ポインター (const*
) に変換し、C++ コードの場合は const
参照 (const&
) に変換します。
パフォーマンスの改善の程度は、使用しているコンパイラ、ライブラリ実装、環境によって異なる可能性があります。
例
結果情報
グループ: パフォーマンス |
言語: C | C++ |
既定値: オフ |
コマンド ライン構文: EXPENSIVE_PASS_BY_VALUE |
影響度: Medium |