C ++ - arve ostream nedbrud på android men ikke windows

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg har implementeret en simpel ostream og streambuf klasse. Af en eller anden grund styrter det, når jeg forsøger at instantiere mit AndroidLogOStream-objekt.


Bemærk: Jeg har stlport\_static i min 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;
    };


Det er barebones, og det kører fint på windows. Det kompilerer fint på android, men det styrker af en eller anden grund. Den sidste linie, den forsøger at udføre, er i \_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;
}


Tilladt Jeg er stadig forvirret på iostreams, men det skal være noget galt med konstruktøren, jeg formoder, at det ikke er gyldigt?

Bedste reference


I en konstruktør initialiseres basisklassen først efterfulgt af alle medlemmerne. Når du kalder baseklassekonstruktøren std::ostream, sender du den adresse til mBuf, som endnu ikke er opbygget. Adgang til et objekt, der endnu ikke er opbygget, har udefineret adfærd.


For at komme rundt om dette kan du omstrukturere dine klasser som følger:


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


Bemærk den rækkefølge, jeg har erklæret mBuf og mStream i AndroidLogOStreamWithBuf: De to felter vil blive initialiseret i den rækkefølge, uanset hvilken rækkefølge de vises i konstruktørens initialiseringsliste. , markering af medlemsfunktionerne som inline i din oprindelige kode var overflødig: Når du definerer en medlemsfunktion i klasseteksten, bliver den automatisk markeret som inlinable.


Om dette er et fornuftigt design til dit system, afhænger af, hvordan du vil bruge disse klasser, men svaret er nok 'nej'.

Andre referencer 1


Som det blev påpeget, er basisklassen først konstrueret, og fra udseendet af det ser basekonstruktøren ud til at gøre noget. Jeg tror ikke, det er meningen, men baseklass destructoren ville også skabe et problem, og det vil kalde pubsync() på stream buffer.


Dette forklarer selvfølgelig problemet, men giver ikke en løsning: Løsningen på dette initialiseringsproblem er at gøre stream-bufferen (eller en brugerdefineret klasse, der indeholder streambufferen som medlem) en virtual base klasse:


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


Grunden til, at basen skal være virtuel, er, at streambufferen er et argument til den virtuelle base std::ios. For at sikre, at din strømbuffer initialiseres, skal den være den venstre virtuelle base.