メインコンテンツ

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

CERT C++: DCL53-CPP

構文的にあいまいな宣言を記述しない

説明

ルール定義

構文的にあいまいな宣言を記述しないようにします。1

Polyspace 実装

ルール チェッカーは、"曖昧な宣言構文" をチェックします。

すべて展開する

問題

この欠陥は、オブジェクト宣言と関数/パラメーター宣言のどちらが意図されたものかを宣言から判断できない場合に発生します。このあいまいさは、多くの場合、最も厄介な解析と呼ばれます。

たとえば、以下の宣言はあいまいです。

  • ResourceType aResource();

    aResourceResourceType 型の変数を返す関数なのか、ResourceType 型のオブジェクトなのか、すぐには理解できません。

  • TimeKeeper aTimeKeeper(Timer());

    aTimeKeeperTimer 型の名前なしオブジェクトで構築されるオブジェクトなのか、パラメーターとして名前なし関数ポインター型をもつ関数なのか、すぐには理解できません。この関数ポインターは、引数がなく戻り値の型が Timer の関数を参照しています。

チェッカーは、グローバル スコープによるあいまいな宣言にフラグを設定します。たとえば、解析では、Type a() の形式を使用したグローバル スコープによる宣言にはフラグが設定されません。ここで、Type は既定のコンストラクターを使用したクラス型です。解析では、aType 型を返す関数として解釈されます。

リスク

宣言があいまいな場合、C++ 規格は構文の特定の解釈を選択します。次に例を示します。

  • ResourceType aResource();
    これは関数 aResource の宣言として解釈されます。

  • TimeKeeper aTimeKeeper(Timer());
    これは、関数ポインター型の名前なしパラメーターをもつ関数 aTimeKeeper の宣言として解釈されます。

開発者またはコード レビュー担当者が別の解釈を想定している場合、予期しない結果になる可能性があります。

たとえば、理解するのが困難なコンパイル エラーが後で発生する場合があります。既定の解釈は関数宣言を示すので、この関数をオブジェクトとして使用すると、コンパイラはコンパイル エラーを報告する可能性があります。このコンパイル エラーは、適切なコンストラクターを使用せずに関数からオブジェクトへの変換が試みられていることを示します。

修正方法

宣言を明確にします。たとえば、これらのあいまな宣言は以下のように修正します。

  • ResourceType aResource();

    オブジェクト宣言:

    宣言が既定のコンストラクターを使用して初期化されたオブジェクトのことを指している場合は、次のように書き換えます。

    ResourceType aResource;
    これは C++11 より前の場合です。または、次のようにします。
    ResourceType aResource{};
    これは、C++11 以降の場合です。

    関数宣言:

    宣言が関数のことを指している場合、関数の typedef を使用します。

    typedef ResourceType(*resourceFunctionType)();
    resourceFunctionType aResource;

  • TimeKeeper aTimeKeeper(Timer());

    オブジェクト宣言:

    宣言がクラス Timer の名前なしオブジェクトで初期化されたオブジェクト aTimeKeeper のことを指している場合、かっこのペアを追加します。

    TimeKeeper aTimeKeeper( (Timer()) );
    これは C++11 より前の場合です。または、中かっこを使用します。
    TimeKeeper aTimeKeeper{Timer{}};
    これは、C++11 以降の場合です。

    関数宣言:

    宣言が関数ポインター型の名前なしパラメーターをもつ関数 aTimeKeeper のことを指している場合、代わりに名前付きパラメーターを使用します。

    typedef Timer(*timerType)();
    TimeKeeper aTimeKeeper(timerType aTimer);

例 – 関数宣言またはオブジェクト宣言
class ResourceType {
      int aMember;
    public:
      int getMember();
};

void getResource() {
    ResourceType aResource(); //Noncompliant
}

この例では、aResource はオブジェクトとして使用される可能性がありますが、宣言の構文は関数宣言を示しています。

修正 — オブジェクト宣言の {} を使用

1 つの修正方法 (C++11 以降) として、オブジェクト宣言の中かっこを使用することができます。


class ResourceType {
      int aMember;
    public:
      int getMember();
};

void getResource() {
    ResourceType aResource{};
}
例 – 名前なしオブジェクト宣言または名前なし関数パラメーター宣言

class MemberType {};

class ResourceType {
      MemberType aMember;
    public:
      ResourceType(MemberType m) {aMember = m;}
      int getMember();
};

void getResource() {
    ResourceType aResource(MemberType());  //Noncompliant
}

この例では、aResourceMemberType 型の名前なしオブジェクトで初期化されたオブジェクトとして使用される可能性がありますが、宣言の構文は関数ポインター型の名前なしパラメーターをもつ関数を示しています。この関数ポインターは、引数がない MemberType 型の関数を指しています。

修正 — オブジェクト宣言の {} を使用

1 つの修正方法 (C++11 以降) として、オブジェクト宣言の中かっこを使用することができます。


class MemberType {};

class ResourceType {
      MemberType aMember;
    public:
      ResourceType(MemberType m) {aMember = m;}
      int getMember();
};

void getResource() {
    ResourceType aResource{MemberType()};
}
例 – 名前なしオブジェクト宣言または名前付き関数パラメーター宣言

class Integer {
	int aMember;
public:
	Integer(int d) {aMember = d;}
	int getMember();
};

int aInt = 0;
void foo(){
	Integer aInteger(Integer(aInt)); //Noncompliant
}

この例では、aInteger は、名前なしオブジェクト Integer(aInt) (変数 aInt を使用して構築されるクラス Integer のオブジェクト) で構築されたオブジェクトである可能性があります。ただし、宣言の構文は aIntegerInteger 型の名前付きパラメーター aInt をもつ関数であることを示しています (余分なかっこは無視されます)。

修正 — オブジェクト宣言の {} を使用

1 つの修正方法 (C++11 以降) として、オブジェクト宣言の {} を使用することができます。


class Integer {
	int aMember;
public:
	Integer(int d) {aMember = d;}
	int getMember();
};

int aInt = 0;
void foo(){
	Integer aInteger(Integer{aInt});
}
修正 — 名前付きパラメーター宣言の余分なかっこを削除

aInteger が名前付きパラメーター aInt をもつ関数の場合、aInt を囲む余分な () を削除します。


class Integer {
       int aMember;
    public:
       Integer(int d) {aMember = d;}
       int getMember();
};

Integer aInteger(Integer aInt);

チェック情報

グループ: 01.宣言と初期化 (DCL)

バージョン履歴

R2019a で導入


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.