C ++ - 继承ostream在Android上崩溃但不在Windows上崩溃

时间:2012-02-28 12:58:56

标签: android c++ windows io iostream

我已经实现了一个简单的ostream和streambuf类。出于某种原因,当我尝试实例化我的AndroidLogOStream对象时它会崩溃。

注意:我的Application.mk中有stlport_static

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;
    };

它是准系统,它在Windows上运行良好。它在android上编译很好,但由于某种原因它崩溃了。它尝试执行的最后一行是在_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;
}

当然,我仍然对iostream很困惑,但构造函数一定有问题,我认为它无效?

2 个答案:

答案 0 :(得分:5)

在构造函数中,首先初始化基类,然后是所有成员。当您调用基类构造函数std::ostream时,您将向其传递尚未构造的mBuf地址。访问尚未构造的对象具有未定义的行为。

要解决这个问题,您可以按照以下方式重新设计课程:

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;
    }
};

请注意我在mBuf中声明mStreamAndroidLogOStreamWithBuf的顺序:这两个字段将按此顺序初始化,无论它们出现在构造函数初始值设定项列表中的顺序如何。另外,在原始代码中将成员函数标记为inline是多余的:当您在类定义中定义成员函数时,它会自动标记为无限。

这对你的系统来说是否合理,取决于你打算如何使用这些类,但答案可能是“不”。

答案 1 :(得分:1)

正如所指出的那样,首先构造基类,从它的外观来看,基类构造函数似乎做了一些事情。我不认为这是有意义的,但是基类析构函数也会产生问题,并且会在流缓冲区上调用pubsync()

当然,这解释了问题,但没有提供解决方案:此初始化问题的解决方案是使流缓冲区(或包含流缓冲区的自定义类作为成员)为virtual库类:

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

基础必须是虚拟的原因是流缓冲区是虚拟基础std::ios的参数。为了确保首先初始化流缓冲区,它必须是最左边的虚拟基础。