メインコンテンツ

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

無効な C++ に固有の演算

C++ 固有の無効演算が発生

説明

C++ コード演算に対するこれらのチェックでは、演算が有効かどうかを判別します。チェックでは、次の一連の無効な動作を探索します。

  • 配列のサイズが厳密に正ではない。

  • typeid 演算子が NULL ポインターをデリファレンスする。

  • dynamic_cast 演算子が無効なキャストを実行する。

  • (C++11 以降) 配列初期化子句の数が初期化する配列要素の数を超えている。

  • (C++11 以降) 配置 new 演算子に対するポインター引数が指しているメモリが十分ではない。

すべて展開する

class License {
protected:
  int numberOfUsers;
  char (*userList)[20];
  int *licenseList;
public:
  License(int numberOfLicenses);
  void initializeList();
  char* getUser(int);
  int getLicense(int);
};

License::License(int numberOfLicenses) : numberOfUsers(numberOfLicenses) {
  userList = new char [numberOfUsers][20];
  licenseList = new int [numberOfUsers];
  initializeList();
}

int getNumberOfLicenses();
int getIndexForSearch();

void main() {
  int n = getNumberOfLicenses();
  if(n >= 0 && n <= 100) {
    License myFirm(n);
    int index = getIndexForSearch();
    myFirm.getUser(index);
    myFirm.getLicense(index);
  }
}

この例では、コンストラクター License::License に対する引数 n は次の 2 つのカテゴリに当てはまります。

  • n = 0:new 演算子がこの引数を使用すると、[無効な C++ に固有の演算] はエラーを生成する。

  • n > 0:new 演算子がこの引数を使用すると、[無効な C++ に固有の演算] はグリーンになる。

2 つのカテゴリの引数を結合して、[無効な C++ に固有の演算]new 演算子でオレンジ エラーを生成します。

この問題を表示するには、オプション環境ポインターが安全でないことを考慮する (-stubbed-pointers-are-unsafe)を有効にします。

#include <iostream>
#include <typeinfo>
#define PI 3.142

class Shape {
public:
  Shape();
  virtual void setVal(double) = 0;
  virtual double area() = 0;
};

class Circle: public Shape {
  double radius;
public:
  Circle(double radiusVal):Shape() {
    setVal(radiusVal);
  }

  void setVal(double radiusVal) {
     radius = radiusVal;
  }

  double area() {
    return (PI * radius * radius);
  }
};


Shape* getShapePtr();

void main() {
  Shape* shapePtr = getShapePtr();
  double val;

  if(typeid(*shapePtr)==typeid(Circle)) {
    std::cout<<"Enter radius:";
    std::cin>>val;
    shapePtr->setVal(val);
    std::cout<<"Area of circle = "<<shapePtr->area();
  }
  else {
    std::cout<<"Shape is not a circle.";
  }

}

この例では、関数 getShapePtr() から返される Shape* ポインター shapePtrNULL の可能性があります。NULL 値の可能性がある shapePtrtypeid 演算子と一緒に使用しているので、[無効な C++ に固有の演算] チェックはオレンジです。

class Base {
public :
  virtual void func() ;
};

class Derived : public Base  {
};

Base* returnObj(int flag) {
  if(flag==0)
    return new Derived;
  else
    return new Base;
}


int main() {

    Base * ptrBase;
    Derived * ptrDerived;

    ptrBase = returnObj(0) ;
    ptrDerived = dynamic_cast<Derived*>(ptrBase); //Correct dynamic cast
    assert(ptrDerived != 0); //Returned pointer is not null

    ptrBase = returnObj(1);
    ptrDerived = dynamic_cast<Derived*>(ptrBase); //Incorrect dynamic cast
    // Verification continues despite red
    assert(ptrDerived == 0); //Returned pointer is null
}

この例では、dynamic_cast 演算子に対する [無効な C++ に固有の演算] が次のようになります。

  • 演算子が Derived にキャストするポインター ptrBase が既に Derived オブジェクトを指している場合はグリーン。

  • 演算子が Derived にキャストするポインター ptrBaseBase オブジェクトを指している場合はレッド。

    通常、レッド チェックが発生すると、そのチェックと同じスコープの検証は中止されます。ただし、ポインターを含む dynamic_cast 演算に対するレッドの [無効な C++ に固有の演算] の後は検証が続行されます。ソフトウェアでは、dynamic_cast 演算子から NULL ポインターが返されると想定されます。

class Base {
public :
  virtual void func() ;
};

class Derived : public Base  {
};

Base& returnObj(int flag) {
  if(flag==0)
    return *(new Derived);
  else
    return *(new Base);
}


int main() {
  Base & refBase1 = returnObj(0);
  Derived & refDerived1 = dynamic_cast<Derived&>(refBase1); //Correct dynamic cast;

  Base & refBase2 = returnObj(1);
  Derived & refDerived2 = dynamic_cast<Derived&>(refBase2); //Incorrect dynamic cast
  // Analysis stops
  assert(1);
}

この例では、dynamic_cast 演算子に対する [無効な C++ に固有の演算] が次のようになります。

  • 演算子が Derived& にキャストする参照 refBase1 が既に Derived オブジェクトを参照している場合はグリーン。

  • 演算子が Derived& にキャストする参照 refBase2Base オブジェクトを参照している場合はレッド。

    ポインターを含む dynamic_cast 演算に対するレッドの [無効な C++ に固有の演算] の後は、ソフトウェアでそのチェックと同じスコープにあるコードは検証されません。たとえば、assert ステートメントに対する [ユーザー アサーション] チェックはソフトウェアで実行されません。

#include <stdio.h>

int* arr_const;

void allocate_consts(int size) {
    if(size>1)
      arr_const = new int[size]{0,1,2};
    else if(size==1)
      arr_const = new int[size]{0,1};
    else
       printf("Nonpositive array size!");
}

int main() {
    allocate_consts(3);
    allocate_consts(1);
    return 0;
}

この例では、[無効な C++ に固有の演算] チェックによって、初期化子句の数と初期化する要素の数が一致しているかどうかを判断します。

allocate_consts の最初の呼び出しでは、サイズが 3 の配列を初期化するために、初期化リストには 3 つの要素があります。new 演算子に対する [無効な C++ に固有の演算] チェックはグリーンです。2 番目の呼び出しでは、初期化リストに 2 つの要素がありますが、初期化する配列のサイズは 1 です。new 演算子に対するチェックはレッドです。

#include <new>

class aClass {
  virtual void func();  
};

void allocateNObjects(unsigned int n) {
    char* location = new char[sizeof(aClass)];
    aClass* objectLocation = new(location) aClass[n];  
}

この例では、ある aClass オブジェクトのサイズに等しいメモリがポインター location に関連付けられています。しかし、関数引数 n に応じて、配置 new 演算子を使用するときに複数のオブジェクトが割り当てられる可能性があります。ポインター location には、このように割り当てられたオブジェクトに対応できる十分なメモリがない場合があります。

チェック情報

グループ: C++
言語: C++
頭字語: CPP