2010-12-17 11 views
6

私はいくつかのコードをWindowsに移植しており、困惑しています。ポインターへのポインターをコピーするために起動時に自動的に実行されるいくつかのコードがあり、それがヌルでない場合にポインターへのポインターを削除するためにexitで再度実行されるコードがあります。ポインタがポインタにない場合のポインタへのポインタの衝突

私は

動作を再現するために
int main() 
{ 
    // Pointer to a Pointer, current crash. 
    InterfaceClass** ptrptr; 
    ConcreteTwo* object = new ConcreteTwo(); 
    ptrptr = (InterfaceClass**)(&object); // cast is required for some reason. 
    delete *ptrptr; // Crash here. 

    // Single pointer, works fine. 
    InterfaceClass* ptrptr; 
    ConcreteTwo* object = new ConcreteTwo(); 
    ptrptr = object; 
    delete ptrptr; 

    // There are other cases where there are only 3 classes in the hierarchy. 
    // This also works fine. 
    InterfaceClass** ptrptr; 
    ConcreteOne* object = new ConcreteOne(); 
    ptrptr = (InterfaceClass**)(&object); 
    delete *ptrptr; 

    return 0; 
} 

をサンプルプログラムを作成したクラス階層は次のようになります。基本クラスは、いくつかの純粋な仮想関数を持つインタフェースであり、多くのオブジェクトが複数の場所から潜在的に継承するような方法で、プログラム全体に多くのクラスによって含まれています。このため、具体的な実装では、「public virtual InterfaceClass」を拡張する必要があります。この例では、「仮想」を削除するとクラッシュが解決されます。

class InterfaceClass { 
public: 
    virtual ~InterfaceClass() {}; 
    InterfaceClass() {} 
}; 

class ConcreteClass : public virtual InterfaceClass { 
public: 
    ConcreteClass() { } 
    virtual ~ConcreteClass() {} 
}; 

class ConcreteOne : public ConcreteClass 
{ 
public: 
    ConcreteOne(void) {} 
    virtual ~ConcreteOne(void) {} 
}; 

class ConcreteTwo : public ConcreteOne 
{ 
public: 
    ConcreteTwo(void) {} 
    virtual ~ConcreteTwo(void) {} 
}; 

答えて

5

ポインタの型は、それが指している型とはまったく関係がないという事実をよく知っていますか?言い換えれば、T1がT2から継承した場合、T1 *もT2 *から継承されているという印象を受けていますか?それは誤解されるだろう。さて、それはあなたの現在の状況にどのように適用されますか?

InterfaceClass** ptrptr; 
    ConcreteTwo* object = new ConcreteTwo(); 
    ptrptr = (InterfaceClass**)(&object); // cast is required for some reason. 

ここでは、Cスタイルキャストの大きな問題があります。それで、水平のスペースを節約しますが、あなたはちょうどあなたがどんなキャストの種類を知っていますか?それはあなたが思うものではありません。実際にreintpret_castをConcreteTwo *タイプから関連のないタイプInterfaceClass *に変更しました。ポインタアドレスは、あなたが言うタイプとは何の関係もありません。

次に、再解釈されたポインタ型をdeleteに投げます。これは速やかに自分自身の括約筋に違反しました。

3

まあ、コンパイラはあなたを警告し、あなたはそれをあなたの方法を行うことを決めた...

あなたは、このキャストはできません。ConcreteTwo

ptrptr = (InterfaceClass**)(&object); 

objectためのポイントを、どのInterfaceClassと同じではありません。 InterfaceClassサブオブジェクトConcreteTwoは別のアドレスにあります。 *ptrptrは、InterfaceClassのインスタンスへのポインタではありません。

deleteに渡すポインタはConcreteTwoへのポインタですが、それはInterfaceClassへのポインタであるとコンパイラに指示しました。 deleteは実際にはInterfaceClassであると想定しているため、クラッシュします。

1

私は問題が鋳造ラインにあると思います。ところで、あなたが挿入したキャストを削除すると、コンパイラは正確に何が問題かを伝えます。

あなたが本当にこれをしたい場合は、途中、私は強く反対助言、あなたが最初の一時を作成する必要があります。

ConcreteTwo* object = new ConcreteTwo(); 
InterfaceClass* ptr = object; 

、あなたはそのアドレスを取得し、ptrptr変数に割り当てることができます。

InterfaceClass** ptrptr = &ptr; 

今は安全に削除することができます。

delete *ptrptr; 

ptrptrptrの前に範囲外になる場合は、削除が再びクラッシュする可能性があることを考慮してください。

その他については、ノアがコードが機能しない理由を説明します。

関連する問題