web-dev-qa-db-ja.com

仮想デストラクタを持たないポリモーフィッククラスタイプのオブジェクトを削除する方法

サードパーティのSDKからコードをコンパイルしようとすると、次のエラーが発生します。

*Description    Resource    Path    Location    Type
deleting object of polymorphic class type ‘Vendor_sys::VendorCode’ which has non-virtual destructor might cause undefined behaviour [-Werror=delete-non-virtual-dtor]   PnServer.cpp    /PCounter   line 467    C/C++ Problem*

ベンダーのSDKの部分的な知識だけでこの条件を満たすことが可能かどうかはわかりません。ここでは、手間のかかる作業のほとんどがdllまたはライブラリオブジェクトで行われます。

私のビルド環境は、gppを使用したEclipseJunoです。

Googleでエラーメッセージを検索しましたが、このエラーのインスタンスは見つかりませんでした。

それで、ベンダーコードのブラックボックス部分を変更できない場合、私のオプションは何ですか?

Makeプロセス中に失敗するコードは次のとおりです。

delete pData->unit;
15
bentaisan

悪いニュース、私は恐れています。そのクラスを基本クラスとして使用しないでください。制約と落とし穴が多すぎます。あなたはそれで逃げるかもしれませんが、なぜそれを危険にさらすのですか?ライブラリベンダーにバグレポートを提出します。

多態的なポインターが必要ない場合は、そのタイプのオブジェクトをクラスに含め、継承するメンバー関数を委任します。

class my_class {
private:
    evil_class evil;
public:
    virtual ~my_class() {/* stuff */}
    virtual int member() { return evil.member(); }
};
11
Jive Dadson

サードパーティのSDKのバグです。基本クラスとして使用されるクラスには、仮想デストラクタが必要です。そうしないと、派生クラスインスタンスのベースへのポインタを削除しても、派生クラスのデストラクタは呼び出されません。

それを回避する1つの方法は、ベースへのポインタを削除しないことです。代わりに、dynamic_castを使用して、派生クラスへのポインターを取得します(そのベースから派生したクラスが多数ある場合、これは不便な場合があります)。

9
user1610015

この警告は、基本クラスに仮想メンバー関数があり、仮想dtorがない場合に生成されます。これはバグです。コードがない場合は、サブクラス内のリソースを手動で割り当て解除していることを確認する以外にできることはありません。カスタムのcleanup()メンバー関数のように、オブジェクトを削除する前に必ず手動で呼び出すようにしてください。

別のオプションはstatic_cast正しいクラスにそれを。ご了承ください dynamic_cast(ランタイムオーバーヘッドが発生し、RTTIが必要)は必要ありません。この場合、コンパイラーはコンパイル時に型の関係をうまく導出できます。

もちろん、コードの一部ではない別の場所でオブジェクトが削除された場合は、運が悪いことになります。その場合、サブクラスが何も割り当てないことを確認してください。そうすれば、デストラクタが呼び出されていなくてもリークすることはありません。

3
Nikos C.

基本クラスで仮想デストラクタが宣言されていない限り、基本クラスへのポインタを安全に使用することはできません。これはベンダーライブラリであるため、必要な仮想デストラクタを追加することはできません。

ライブラリ自体がこのオブジェクトのサブクラスを作成しない場合は、このオブジェクトのサブクラスを宣言し、そのオブジェクトを基本クラスとして使用することで、必要な効果を得ることができる場合があります。

class NotGoodBase {
 ~NotGoodBase(); // Non-virtual destructor.  Possibly added by compiler.
};

class UseThisAsBase : public NotGoodBase {
 virtual ~UseThisAsBase(); // Virtual destructor.
};

代入や変数を参照で渡す場合など、NotGoodBase型のLValueが必要な場所を除いて、NotGoodBaseを使用できる場所であればどこでもUseThisAsBase型のポインターを使用できるはずです。

2
Greg Fisher

このシナリオでは、ここからコンパイルフラグを削除するのではなく、クラスに仮想デストラクタを追加する必要があります。

例えば。クラスMyclassの場合、このエラーが発生し、追加します

virtual ~Myclass(){}

この魂を試してみてください、それはうまくいくでしょう。

1
spt025