メインコンテンツ

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

MISRA C++:2023 Rule 21.6.5

A pointer to an incomplete class type shall not be deleted

R2024b 以降

説明

ルール定義

A pointer to an incomplete class type shall not be deleted. 1

根拠

不完全なクラスを指すポインターを削除すると、そのクラスに含まれている可能性のある非トリビアル デストラクターを呼び出せなくなります。デストラクターでメモリ割り当て解除などのクリーンアップ アクティビティを実行している場合、これらのアクティビティが発生しません。

同様の問題は、たとえば、不完全なクラスを指すポインターにダウンキャストする場合に発生します (ダウンキャストとは、基底クラスを指すポインターから派生クラスを指すポインターにキャストすることです)。ダウンキャストの時点では、基底クラスと派生クラスの関係は不明です。特に、派生クラスが複数のクラスから継承している場合、ダウンキャストの時点ではこの情報を利用できません。ダウンキャストでは多重継承に必要な調整を加えることができず、その結果のポインターはデリファレンスできません。

Polyspace 実装

チェッカーは、不完全なクラスを指すポインターが削除またはキャストされている状況にフラグを設定します。不完全なクラスとは、そのクラスが使用される時点でその定義が可視になっていないポインターのことです。

たとえば、クラス Body の定義は、delete 演算子が Body のポインターに対して呼び出されたときには可視ではありません。

class Handle {
  class Body *impl;  
public:
  ~Handle() { delete impl; }
  // ...
};

トラブルシューティング

ルール違反が想定されるものの、Polyspace® から報告されない場合は、コーディング規約違反が想定どおりに表示されない理由の診断を参照してください。

すべて展開する

class Handle {
  class Body *impl;  
public:
  ~Handle() { delete impl; }     //Noncompliant
  // ...
};

この例では、Body を指すポインターが削除されるとき、クラス Body の定義は可視ではありません。

修正 — 削除の前にクラスを定義

1 つの修正方法として、クラスを指すポインターを削除するときにクラス定義が可視になるようにします。

class Handle {
  class Body *impl;  
public:
  ~Handle();
  // ...
};
 
// Elsewhere
class Body { /* ... */ };
  
Handle::~Handle() {
  delete impl;          
}
修正 — std::shared_ptr を使用

別の修正方法として、通常のポインターの代わりに std::shared_ptr 型を使用します。

#include <memory>
  
class Handle {
  std::shared_ptr<class Body> impl;
  public:
    Handle();
    ~Handle() {}
    // ...
};

File1.h:

class Base {
protected:
  double var;
public:
  Base() : var(1.0) {}
  virtual void do_something();
  virtual ~Base();
};

File2.h:

void funcprint(class Derived *);
class Base *get_derived(); 

File1.cpp:

#include "File1.h"
#include "File2.h"
 
void getandprint() {
  Base *v = get_derived();
  funcprint(reinterpret_cast<class Derived *>(v));    //Noncompliant
}

File2.cpp:

#include "File2.h"
#include "File1.h"
#include <iostream>
 
class Base2 {
protected:
  short var2;
public:
  Base2() : var2(12) {}
};
 
class Derived : public Base2, public Base {
  float var_derived;
public:
    Derived() : Base2(), Base(), var_derived(1.2f) {}
    void do_something()
    {
        std::cout << "var_derived: "
                  << var_derived << ", var : " << var
                  << ", var2: " << var2 << std::endl;
    }
 };
 
void funcprint(Derived *d) {
  d->do_something();
}
 
Base *get_derived() {
  return new Derived;
}

この例では、Base* ポインターを Derived* ポインターにダウンキャストするときに、クラス Derived の定義が File1.cpp 内で可視になっていません。

File2.cpp では、クラス Derived は 2 つのクラス Base および Base2 から派生しています。File1.cpp では多重継承に関する情報がダウンキャストの時点では利用できません。ダウンキャストの結果は関数 funcprint に渡され、funcprint の本体内でデリファレンスされます。ダウンキャストが不完全な情報を使用して行われたため、デリファレンスは無効になる可能性があります。

修正 — ダウンキャストの前にクラスを定義

1 つの修正方法として、Base* ポインターを Derived* ポインターにダウンキャストする前に、クラス Derived を定義します。

この修正例の File2.cpp では、クラス Derived の定義が可視になっている時点で、funcprint の本体内でダウンキャストが行われています。Derived の定義が可視になっていない File1.cpp では、ダウンキャストが行われていません。前の不適切な例からの変更が強調表示されています。

File1_corr.h:

class Base {
protected:
  double var;
public:
  Base() : var(1.0) {}
  virtual void do_something();
  virtual ~Base();
};

File2_corr.h:

void funcprint(class Base *);
class Base *get_derived(); 

File1.cpp:

#include "File1_corr.h"
#include "File2_corr.h"
 
void getandprint() {
  Base *v = get_derived();
  funcprint(v);
}

File2.cpp:

#include "File2_corr.h"
#include "File1_corr.h"
#include <iostream>
 
class Base2 {
protected:
  short var2;
public:
  Base2() : var2(12) {}
};
 
class Derived : public Base2, public Base {
  float var_derived;

public:
    Derived() : Base2(), Base(), var_derived(1.2f) {}
    void do_something()
    {
        std::cout << "var_derived: "
                  << var_derived << ", var : " << var
                  << ", var2: " << var2 << std::endl;
    }
};
 
void funcprint(Base *d) {
  Derived *temp = dynamic_cast<Derived*>(d);
  if(temp)  {
     d->do_something();
  }
  else {
      //Handle error
  }
}
 
Base *get_derived() {
  return new Derived;
}

チェック情報

グループ: 言語サポート ライブラリ
カテゴリ: 必要

バージョン履歴

R2024b で導入


1 All MISRA coding rules and directives are © Copyright The MISRA Consortium Limited 2021.

The MISRA coding standards referenced in the Polyspace Bug Finder™ documentation are from the following MISRA standards:

  • MISRA C:2004

  • MISRA C:2012

  • MISRA C:2023

  • MISRA C++:2008

  • MISRA C++:2023

MISRA and MISRA C are registered trademarks of The MISRA Consortium Limited 2021.