【问题标题】:C++ - inheriting ostream crashes on android but not windowsC++ - 在android上继承ostream崩溃但不是windows
【发布时间】:2012-03-17 22:48:05
【问题描述】:

我已经实现了一个简单的 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;
}

虽然我对 iostreams 仍然很困惑,但它一定是构造函数有问题,我想它是无效的?

【问题讨论】:

  • 查看this old answer 获取一些有用的链接。
  • 为什么是android和c++标签?我可以得到 C++ 一个,但不是另一个!
  • 我正在使用 android ndk 在 android 上运行它:p

标签: android c++ windows io iostream


【解决方案1】:

在构造函数中,首先初始化基类,然后是所有成员。当你调用基类构造函数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;
    }
};

请注意我在AndroidLogOStreamWithBuf 中声明mBufmStream 的顺序:这两个字段将按该顺序初始化,无论它们在构造函数初始化列表中出现的顺序如何。顺便说一句,在原始代码中将成员函数标记为 inline 是多余的:当您在类定义中定义成员函数时,它会自动标记为可内联。

这对您的系统而言是否明智的设计取决于您打算如何使用这些类,但答案可能是否定的。

【讨论】:

  • 啊啊啊!这是一个好点!不过有一件事:为什么它在 Windows 上运行良好?
  • 不幸的是,未定义行为的一个可能结果是“运行良好”。
  • 我将如何解决这个问题?我的意思是我需要在 ostream 构造函数中将缓冲区作为引用传递!
  • 在那里,我用一些更实用的建议更新了我的答案。我怀疑适合您情况的最佳解决方案会有所不同,具体取决于周围代码的设计。
【解决方案2】:

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

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

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

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

【讨论】:

  • 如果我声明它是虚拟的,它会在我的 AndroidLogOStream () 构造函数中显示“mBuf 未定义”,我必须在构造函数中使用 mBuf。如何解决这个问题?
  • 好吧,它不再是成员,而是基类!你可以使用this。或者,您将其放入自定义结构中并使用它作为虚拟基础。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-25
  • 2011-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多