CERT.OOP.CTOR.VIRTUAL_FUNC

仮想関数は、コンストラクタまたはデストラクタから呼び出すことは許可されませんが、次のような例外では、コンストラクタまたはデストラクタから呼び出すことができます。

  • OOP50-CPP-EX1: 明示的に修飾された ID で仮想関数を呼び出すことは許可されています。

  • OOP50-CPP-EX2: コンストラクタまたはデストラクタから最終的な virt-specifier を持つ仮想関数を呼び出すことは許可されています。また、最終的な class-virt-specifier を持つクラスのコンストラクタまたはデストラクタから仮想関数を呼び出すこともできます。

脆弱性とリスク

コンストラクタまたはデストラクタから仮想関数を呼び出すことは、次の理由により避ける必要があります。構築中、派生クラスにはリソースを初期化する機会がなかった可能性があります。同様に、より多くの派生クラスで、デストラクタから関数を呼び出そうとすると、既に解放されているリソースにアクセスする可能性があります。

軽減と防止

コンストラクタまたはデストラクタから仮想関数を呼び出さないでください。

例外 OOP50-CPP-EX1 と OOP50-CPP-EX2 では、ガイダンスを使用して、指摘を回避することもできます。

脆弱コード例

コピー
     struct A {
      void seize_mine();
      void seize_fun();
      A()
      {
          seize();
          seize_mine();
      }
      virtual ~A()
     {
         release();
         seize_fun();
     }
   protected
     virtual void seize();
     virtual void release();
 };

 struct B : A{
   B():A() {      //OOP50-CPP-EX1: 明示的に修飾された ID で仮想関数を呼び出すことは許可されています。
     B::seize();
     B::release();
   }
 };

 struct base {
   base();
   virtual void f();
 };

 struct derived : base {
   derived() : base() {     // OOP50-CPP-EX2: 最終的な virt-specifier を持つコンストラクタまたはデストラクタから仮想関数を呼び出すことは許可されています。
     f();
   }
   void f() override final;
 };

 struct derived2 final : base {
   derived1() : base1() {     // OOP50-CPP-EX2: クラスが最後である場合、コンストラクタまたはデストラクタから仮想関数を呼び出すことは許可されています。
     f();
   }
   void f() override;
 };

この非準拠の例では、Klocwork は 6 行目と 11 行目で CERT.OOP.CTOR.VIRTUAL_FUNC の欠陥を報告します。これは、コンストラクタまたはデストラクタで仮想関数を呼び出すと、上書きするメカニズムが無効になっているため、予期しない結果が生じる可能性があるためです。明示的に修飾された ID で仮想関数を呼び出すことは許可されています。また、最終的な class-virt-specifier を持つクラスのコンストラクタまたはデストラクタから仮想関数を呼び出すこともできます。

修正コード例

コピー
    struct A {
      void seize_mine();
      void seize_fun();
      A()
      {
          seize_mine();
      }
      virtual ~A()
      {
         seize_fun();
     }
   protected
     virtual void seize();
     virtual void release();
 };

 struct B : A{
   B():A() {   //OOP50-CPP-EX1: 明示的に修飾された ID で仮想関数を呼び出すことは許可されています。
     B::seize();
     B::release();
   }
 };

 struct base {
   base();
   virtual void f();
 };

 struct derived : base {
   derived() : base() {   // OOP50-CPP-EX2: It is permissible to call a virtual function from a constructor or destructor that has the final virt-specifier
     f();
   }
   void f() override final;
 };

 struct derived2 final : base {
   derived1() : base1() {   // OOP50-CPP-EX2: クラスが最後である場合、コンストラクタまたはデストラクタから仮想関数を呼び出すことは許可されています。
     f();
   }
   void f() override;
 };

上記の例は、コンストラクタまたはデストラクタから仮想関数を呼び出していないため、準拠しています。