2012-02-28 3 views
2

シンプルなostreamおよびstreambufクラスを実装しました。何らかの理由で、AndroidLogOStreamオブジェクトをインスタンス化しようとするとクラッシュします。C++ - アンドロイド上でostreamクラッシュを継承しますがウィンドウは継承しません。

注:私は私のApplication.mkに

class AndroidLogStreamBuf : public std::streambuf 
    { 
    public: 
     inline AndroidLogStreamBuf() : std::streambuf() 
     { 
      //std::cout << "asdfg"; 

     } 

     inline ~AndroidLogStreamBuf() 
     { 

     } 



    }; 

    class AndroidLogOStream : public std::ostream 
    { 
    public: 
     inline AndroidLogOStream() : std::ostream(&mBuf) 
     { 

     } 

     inline ~AndroidLogOStream() 
     { 

     } 

    private: 
     AndroidLogStreamBuf mBuf; 
    }; 

をstlport_staticを持っていることは必要最小限だし、それはWindows上で正常に動作します。それはアンドロイドでうまくコンパイルされますが、何らかの理由でクラッシュします。それが実行しようと最後の行は_streambuf.cである:46:

私は入出力ストリームにまだかなり混乱していますが、それはコンストラクタと間違って何かでなければならない、私はそれが有効でないと仮定確か
template <class _CharT, class _Traits> 
locale 
basic_streambuf<_CharT, _Traits>::pubimbue(const locale& __loc) { 
    this->imbue(__loc);   <---- crash 
    locale __tmp = _M_locale; 
    _M_locale = __loc; 
    return __tmp; 
} 

+0

いくつかの便利なリンクについては、[この古い回答](http://stackoverflow.com/a/528661/440558)を参照してください。 –

+0

なぜアンドロイドとC++タグ?私はC + + 1を得ることができますが、他の人はいません! –

+0

アンドロイドでアンドロイドでndkを実行しています:p – KaiserJohaan

答えて

5

コンストラクタでは、最初に基本クラスが初期化され、その後にすべてのメンバーが初期化されます。基本クラスのコンストラクタstd::ostreamを呼び出すと、まだ構築されていないmBufのアドレスが渡されます。まだ構築されていないオブジェクトにアクセスすると、未定義の動作が発生します。この問題を回避するには

次のように、あなたのクラスを再設計することができます:関係なく、2つのフィールドはその順序で初期化されます、:

class AndroidLogStreamBuf : public std::streambuf 
{ 
public: 
    AndroidLogStreamBuf() : std::streambuf() 
    { } 

    ~AndroidLogStreamBuf() 
    { } 
}; 

class AndroidLogOStream : public std::ostream 
{ 
public: 
    AndroidLogOStream(AndroidLogStreamBuf *buf) : 
     std::ostream(buf), 
     mBuf(buf) 
    { } 

    ~AndroidLogOStream() 
    { } 

private: 
    AndroidLogStreamBuf *mBuf; 
}; 

class AndroidLogOStreamWithBuf 
{ 
private: 
    AndroidLogStreamBuf mBuf; 
    AndroidLogOStream mStream; 

public: 
    AndroidLogOStreamWithBuf() : 
     mBuf(&mStream), 
     mStream() 
    { } 

    virtual ~AndroidLogOStreamWithBuf() 
    { } 

    AndroidLogOStream& getOStream() 
    { 
     return mStream; 
    } 
}; 

お知らせ私はAndroidLogOStreamWithBufmBufmStreamを宣言したためそれらはコンストラクタの初期化子リストに表示されます。さて、元のコードにメンバー関数をinlineとしてマークするのは余計でした。クラス定義内でメンバー関数を定義すると、自動的にinlinableとしてマークされます。

これがシステムの分かりやすい設計であるかどうかは、これらのクラスの使い方によって異なりますが、その答えはおそらく「いいえ」です。

+0

Ahhhh!それは良い点です!しかし、Windows上でうまく動作するのはなぜですか? – KaiserJohaan

+0

未定義の動作の1つの可能な結果は残念なことに "うまく動作しています"。 – uesp

+0

どうすればこの問題を解決できますか?つまり、ostreamコンストラクタでバッファをレフェレンスとして渡す必要があるということです。 – KaiserJohaan

1

先に指摘したように、基本クラスが最初に構築され、その外観から、基本クラスのコンストラクタは何かを行うようです。私はそれが意味するとは思わないが、基本クラスのデストラクタも問題を作成し、それはストリームバッファ上でpubsync()を呼び出します。もちろん

、この問題を説明するが、解決策を提供していません。この初期化の問題を解決するには、ストリームバッファ(またはメンバーとしてストリームバッファを含むカスタムクラス)virtual基本クラスを作ることです。

class oandroidligstream: 
    virtual AndroidLogStream, 
    public std::ostringstream { 
     ... 
    } 
}; 

ベース仮想なければならない理由は、ストリームバッファは、仮想ベースstd::iosへの引数であることです。ストリームバッファが最初に初期化されることを確認するには、一番左の仮想ベースでなければなりません。

+0

私はそれを仮想宣言すると、私のAndroidLogOStream()コンストラクタで 'mBuf is undefined'と表示され、コンストラクタでmBufを使用する必要があります。どのように解決するのですか? – KaiserJohaan

+0

もうメンバーではなく、基本クラスです! 'this'を使うことができます。あるいは、それをカスタム構造体に入れ、これを白内障の基盤にします。 –