1

以下のコードでわかるように、抽象基本クラス "HostWindow" と、そこから派生するクラス "Chrome" があります。すべての機能は Chrome で実装されています。問題は、仮想の場合、Chrome で関数を呼び出せないことです。

class HostWindow : public Noncopyable {
public:
    virtual ~HostWindow() { }

    // Pure virtual functions:
    virtual void repaint(const IntRect&, bool contentChanged, bool immediate = false, bool repaintContentOnly = false) = 0;
    virtual void scrollbarsModeDidChange() const = 0;
}

class Chrome : public HostWindow {
    // HostWindow functions:
    virtual void repaint(const IntRect&, bool contentChanged, bool immediate = false, bool repaintContentOnly = false);
    virtual void scrollbarsModeDidChange() const;

    void focus() const;
}

たとえば、Chrome のインスタンスがあり、いくつかの関数を呼び出すとします。

WebCore::Chrome *chrome = new Chrome();
chrome->repaint(IntRect(), true); // Null pointer error
chrome->focus(); // returns void (works)

仮想関数を呼び出すたびに発生するヌル ポインター エラーは次のとおりです。

プログラムは信号 EXC_BAD_ACCESS を受信しました。メモリにアクセスできませんでした。理由: アドレス: 0x00000008 の KERN_PROTECTION_FAILURE

何が起こっているのか分かりますか?

更新: 多くの人が指摘したように、このコードは実際に実行されます。残念ながら、コードは WebCore (WebKit) の奥深くにあるため、これ以上完全な例を提供することはできません。しかし、私は問題を絞り込みました。Chrome インスタンスを手動で作成すると、仮想関数の呼び出しが機能します。したがって、問題はこの特定のクロム インスタンスにあり、適切にインスタンス化できません。これで、Chrome インスタンスは別のクラスのコンストラクターでインスタンス化されます。さらに調べてみます…

更新 2: 問題のあるインスタンスの vtable を調べると、それが null であることがわかります。GDB から:

p *(void **)chrome
$52 = (void *) 0x0

通常のインスタンスには正しい vtable があります。では、なぜ vtable が nil なのかを解明する必要があります。どうしてそうなったのだろうか? 他のクラスのコンストラクターでインスタンス化されているためでしょうか。

更新 3: 別のクラスのコンストラクター内でのインスタンス化であるという問題について、私は正しいようです。

したがって、インスタンス化前は次のようになります。

Page::Page(ChromeClient* chromeClient, ...)
    : m_chrome(new Chrome(this, chromeClient))

m_chrome は無効なインスタンスであり、vtable はありません。インスタンス化を変更したので、変数が初めて必要になったときに発生します (これには、後で使用するために ChromeClient を保存する必要があります)。

Page::Page(ChromeClient* chromeClient, ...)
    : m_chrome(0)
    , m_chrome_client(chromeClient)

Chrome* Page::chrome() const {
  if(!m_chrome) {
    m_chrome = new Chrome(this, m_chrome_client);
  }
  return m_chrome;
}

これで、Page::chrome() インスタンスが適切な vtable を備えた正しいインスタンスになりました。かなり奇妙です!

更新 4: 最後の更新、約束します :)。わかりましたので、正確に特定しました。Page コンストラクターの本体でインスタンス化すると、vtable を使用して正しいインスタンスを取得できます。Page コンストラクターのヘッドでインスタンス化すると、vtable がありません。コンストラクターの頭で実行できる変数設定の種類に制限はありますか? それは別の Stackoverflow の質問だと思います。

とても役に立ってくれてありがとう。

4

5 に答える 5

2

はい、「this」ポインターはゼロです。オフセットを取得するために 8 を追加すると、あなたの責任です。どうやら実際のオブジェクトはまったくありません。

実際に理解するのに十分なコードを投稿していないので、私は推測しています。this ポインター全体が 0 であるか、仮想関数テーブル ポインターが 0 である可能性があります。これは、おそらくオブジェクトが作成された後、呼び出しを試みる前に削除されたためです。

私があなたにできる最善のアドバイスは、もっと小さい試験管を作ることです。問題を見つけるか、投稿可能な例になります。

vtbl は、構築プロセスが終了するまでインスタンスに配置されません。実際、この仕様では、クラス階層の構築状態に合わせて vtbl を段階的に変更する必要があります。

于 2010-01-12T13:44:33.297 に答える
0

これは、すべてのシンボルのエクスポートを許可したことが原因であることがわかりました。

通常、WebCore には、基本的に WebKit が必要とするシンボルのサブセットのみがエクスポートされます。

すべてのシンボルをエクスポートするように変更しましたが、どういうわけかこのエラーが発生しました。

于 2010-01-27T13:00:22.593 に答える
0

あなたのコピー不可が次のようになっていると仮定します(少なくとも私の場合はそうでした)

class NonCopyable
{
protected:
    NonCopyable() {}
    ~NonCopyable() {}
private:
    NonCopyable( const NonCopyable& );
    const NonCopyable& operator=( const NonCopyable& );
};

クラスchromeの関数にパブリック修飾子を挿入し、それらのダミー実装を挿入した後、すべてが問題なく機能しました。

投稿されたコードに問題はありません。間違ったことをしていて、それらの部分をここに投稿していない可能性があります。

最後に、割り当ての失敗をチェックする DO。(はい、「新規」はヒープへの割り当てです)

于 2010-01-13T03:19:21.967 に答える
0

完全なコードを投稿できますか?

コードを少し変更した後(利用可能なものは何でも)、動作します:

#include <iostream>

class HostWindow  {
public:
    virtual ~HostWindow() { }

    // Pure virtual functions:
    virtual void repaint(const int , bool contentChanged, bool immediate = false, bool repaintContentOnly = false) = 0;
    virtual void scrollbarsModeDidChange() const = 0;
};

class Chrome : public HostWindow {
public:
    // HostWindow functions:
    virtual void repaint(const int , bool contentChanged, bool immediate = false, bool repaintContentOnly = false) 
    {
        std::cout << "In repaint." << std::endl;
    }
    virtual void scrollbarsModeDidChange() const { }

    void focus() const
    {
        std::cout << "In focus." << std::endl;
    }
};

int main()
{
    Chrome *chrome = new Chrome();
    chrome->repaint(1, true); // Null pointer error
    chrome->focus();
    delete chrome;
    return 0;
}
于 2010-01-12T14:16:48.410 に答える
0

私はあなたが持っているコードベースに精通していませんが、次のように書くべきではありません:

// note the 'WebCore::Chrome()'
WebCore::Chrome *chrome = new WebCore::Chrome();
chrome->repaint(IntRect(), true); // 'chrome' should be a valid pointer now

それ以外の:

WebCore::Chrome *chrome = new Chrome();
chrome->repaint(IntRect(), true); // Null pointer error
于 2010-01-12T15:08:08.510 に答える