2

I have a strange behaviour on a project that I am doing for my kids. I want to parse an xml with rapidXml and play mp3 with bass on my RasPi1B. Everything works fine if I just press it in one main-function. But as soon as I put the code into another class, my xml-data gets corrupted. I only do c++ in my privat time and work with managed languages, so I am not that into memory-management in c++. So I hope you people can help me (and my kids) out of this issue. Of course I could do everything in just one class, but brain would try to choke me to death ;-)

First of all in a single main function:

// test.cpp

#include <iostream>
#include <rapidxml.hpp>
#include <rapidxml_utils.hpp>
#include <rapidxml_print.hpp>
#include <bass.h>

using namespace std;
using namespace rapidxml;

int main(int argc, char **argv)
{
    file<> xmlFile("bin/test.xml");

    xml_document<> doc;
    doc.parse<0>(xmlFile.data());

    print(std::cout, doc, 0); // everything is fine

    bool init = BASS_Init(-1, 44100, 0, 0, NULL);
    cout << "BASS_Init " << (init ? "true" : "false") << " [error: " << BASS_ErrorGetCode() << "]" << endl;

    print(std::cout, doc, 0); // everything is fine

    return 0;
}

Then (nearly) the same with a main function and a class/header:

//test2.cpp

#include <iostream>

#include "player.hpp"

using namespace std;
using namespace player;

int main(int argc, char **argv)
{
    Player* _pPlayer = new Player();
    _pPlayer->loadXml();

    _pPlayer->printXml();       
    _pPlayer->initPlayer();
    _pPlayer->printXml();

    return 0;
}



// player.cpp

#include "player.hpp"

using namespace std;
using namespace rapidxml;

namespace player {
    void Player::loadXml(void)
    {
        file<> xmlFile("bin/test.xml");
        doc.parse<0>(xmlFile.data());
    }

    void Player::printXml(void)
    {
        print(std::cout, doc, 0);
    }

    void Player::initPlayer(void)
    {
        bool init = BASS_Init(-1, 44100, 0, 0, NULL);
        cout << "BASS_Init " << (init ? "true" : "false") << " [error: " << BASS_ErrorGetCode() << "]" << endl;
    }
}



// player.hpp

#include <iostream>

#include <rapidxml.hpp>
#include <rapidxml_utils.hpp>
#include <rapidxml_print.hpp>
#include <bass.h>

using namespace std;
using namespace rapidxml;

namespace player {
    class Player
    {
        public:
            void loadXml(void);
            void printXml(void);
            void initPlayer(void);
        private:
            xml_document<> doc;
    };
}

Compiling with:

BASS_PATH = ../libraries/bass_arm
BASS_INCLUDE_PATH = -I$(BASS_PATH)
BASS_LIBRARY_PATH = -L$(BASS_PATH) -L$(BASS_PATH)/hardfp
BASS_LIBS = -lbass -lm
BASS_LINKER_FLAGS = -Wl,-rpath,$(BASS_PATH):$(BASS_PATH)/hardfp

RAPIDXML_PATH = ../libraries/rapidxml-1.13
RAPIDXML_INCLUDE_PATH = -I$(RAPIDXML_PATH)
RAPIDXML_LIBRARY_PATH = -L$(RAPIDXML_PATH)

test:
    g++ -std=c++11 src_test/test.cpp -o bin/test $(BASS_INCLUDE_PATH) $(RAPIDXML_INCLUDE_PATH) $(BASS_LIBRARY_PATH) $(RAPIDXML_LIBRARY_PATH) $(BASS_LIBS) $(BASS_LINKER_FLAGS)

test2:
    g++ -std=c++11 -g -c src_test/test2.cpp -o src_test/test2.o $(BASS_INCLUDE_PATH) $(RAPIDXML_INCLUDE_PATH)
    g++ -std=c++11 -g -c src_test/player.cpp -o src_test/player.o $(BASS_INCLUDE_PATH) $(RAPIDXML_INCLUDE_PATH)
    g++ -std=c++11 -g src_test/test2.o src_test/player.o -o bin/test2 $(BASS_LIBRARY_PATH) $(RAPIDXML_LIBRARY_PATH) $(BASS_LIBS) $(BASS_LINKER_FLAGS)

My test.xml looks like this:

<?xml version="1.0" encoding="utf-8"?>
<library>
    <series>
        <title>Lorem ipsum A</title>
        <episode>
            <title>dolor sit amet 1</title>
            <cover></cover>
            <files rfid="x1" current_file="1" timestamp="0">
                <file>consetetur/sadipscing_elitr_11.mp3</file>
                <file>consetetur/sadipscing_elitr_12.mp3</file>
                <file>consetetur/sadipscing_elitr_13.mp3</file>
                <file>consetetur/sadipscing_elitr_14.mp3</file>
            </files>
        </episode>
        <episode>
            <title>dolor sit amet 2</title>
            <cover></cover>
            <files rfid="x2" current_file="1" timestamp="0">
                <file>consetetur/sadipscing_elitr_21.mp3</file>
                <file>consetetur/sadipscing_elitr_22.mp3</file>
                <file>consetetur/sadipscing_elitr_23.mp3</file>
                <file>consetetur/sadipscing_elitr_24.mp3</file>
            </files>
        </episode>
    </series>
</library>

And here is the output of sudo bin/test

<library>
        <series>
                <title>Lorem ipsum A</title>
                <episode>
                        <title>dolor sit amet 1</title>
                        <cover/>
                        <files rfid="x1" current_file="1" timestamp="0">
                                <file>consetetur/sadipscing_elitr_11.mp3</file>
                                <file>consetetur/sadipscing_elitr_12.mp3</file>
                                <file>consetetur/sadipscing_elitr_13.mp3</file>
                                <file>consetetur/sadipscing_elitr_14.mp3</file>
                        </files>
                </episode>
                <episode>
                        <title>dolor sit amet 2</title>
                        <cover/>
                        <files rfid="x2" current_file="1" timestamp="0">
                                <file>consetetur/sadipscing_elitr_21.mp3</file>
                                <file>consetetur/sadipscing_elitr_22.mp3</file>
                                <file>consetetur/sadipscing_elitr_23.mp3</file>
                                <file>consetetur/sadipscing_elitr_24.mp3</file>
                        </files>
                </episode>
        </series>
</library>
BASS_Init true [error: 0]
<library>
        <series>
                <title>Lorem ipsum A</title>
                <episode>
                        <title>dolor sit amet 1</title>
                        <cover/>
                        <files rfid="x1" current_file="1" timestamp="0">
                                <file>consetetur/sadipscing_elitr_11.mp3</file>
                                <file>consetetur/sadipscing_elitr_12.mp3</file>
                                <file>consetetur/sadipscing_elitr_13.mp3</file>
                                <file>consetetur/sadipscing_elitr_14.mp3</file>
                        </files>
                </episode>
                <episode>
                        <title>dolor sit amet 2</title>
                        <cover/>
                        <files rfid="x2" current_file="1" timestamp="0">
                                <file>consetetur/sadipscing_elitr_21.mp3</file>
                                <file>consetetur/sadipscing_elitr_22.mp3</file>
                                <file>consetetur/sadipscing_elitr_23.mp3</file>
                                <file>consetetur/sadipscing_elitr_24.mp3</file>
                        </files>
                </episode>
        </series>
</library>

And the output of sudo bin/test2:

<library>
        <series>
                <title>Lorem ipsum A</title>
                <episode>
                        <title>dolor sit amet 1</title>
                        <cover/>
                        <files rfid="x1" current_file="1" timestamp="0">
                                <file>consetetur/sadipscing_elitr_11.mp3</file>
                                <file>consetetur/sadipscing_elitr_12.mp3</file>
                                <file>consetetur/sadipscing_elitr_13.mp3</file>
                                <file>consetetur/sadipscing_elitr_14.mp3</file>
                        </files>
                </episode>
                <episode>
                        <title>dolor sit amet 2</title>
                        <cover/>
                        <files rfid="x2" current_file="1" timestamp="0">
                                <file>consetetur/sadipscing_elitr_21.mp3</file>
                                <file>consetetur/sadipscing_elitr_22.mp3</file>
                                <file>consetetur/sadipscing_elitr_23.mp3</file>
                                <file>consetetur/sadipscing_elitr_24.mp3</file>
                        </files>
                </episode>
        </series>
</library>

BASS_Init true [error: 0]
<l1▒B>
        CJ>
                <>▒CJ▒BJ▒BJ</>
                <device>
                        <de>aults.pcm.device</de>
                        <`CJ/>
                        <8CJ BJ="" iec958="1" 1▒CJ="">
                                <>▒DJ▒BJ6Jcardp3</>
                                <ults>pcm.cardr/1▒CJ▒CJ</ults>
                                <▒CJ>devicesg_edefault</▒CJ>
                                <1>DJPDJ▒CJ(DJ▒CJ</1>
                        </8CJ>
                </device>
                <EJpE>
                        <▒>J▒CJ6J</▒>
                        <cover/>
                        <cm.ca did="" J▒DJ="" pEJ="J">
                                <>devicesdipdefaults.pcm.d</>
                                <>@EJ▒DJEJ▒DJ</>
                                <rmat>rawur/sadip1▒EJ▒EJ</rmat>
                                <▒DJ>6Jtrueltstr_fi</▒DJ>
                        </cm.ca>
                </EJpE>
        <CJ>
</l1▒B>

Sorry for the long post! I hope someone can help me. I feel really lost... Thanks in advance!

1 Answers1

1

xmlFile gets destroyed when Player::loadXml() goes out of scope. This allows the memory that is occupied by the data of xmlFile to be assigned to something else (in this case BASE_Init seems to be writing data to it).

doc is still using the data that xmlFile used to be. This leads to undefined behavior.

Please store xmlFile in the Player class, like you did with doc.

Also don't forget to delete everything you new, like _pPlayer ;-)

KompjoeFriek
  • 3,572
  • 1
  • 22
  • 35
  • oh yeah, you made my day! I thought all the time, that xmlFile isn't used after doc.parse()... Even though, this rapidxml_utils (where file<> is defined) gave me some hard minutes too, because I didn't knew how to handle the whole template-stuff (not in templates yet, but looks a bit like generics in java). I solved it by adding `file<>* pXmlFile;` to the **.hpp** and `pXmlFile = new file<>("bin/test.xml");` to the **.cpp**. Works fine so far, but is it the right way? (edit: poor formatting-options in comments ^^) – FatalDiskError Dec 21 '15 at 23:13
  • Also as an addition: yes, in my "production code" I use `delete`. I just wanted to keep the example as short as possible. – FatalDiskError Dec 21 '15 at 23:17
  • Using a pointer to a `file<>*` is **a** right way. Another way could be without pointers, using the constructor of `Player` to initialize your `file<> xmlFile`. After the `public:` in your `Player` class, you could add: `Player() : xmlFile("bin/test.xml") {}` – KompjoeFriek Dec 22 '15 at 00:33
  • Thanks again! I can live with **a** right way ;-) I know there is most of the time more than one good way. I intentionally didn't used the constructor-approach, because in the "real" program the loaded xml varies on which user uses the app. But yes, I also thought about this solution. Anyways, pointer is working like a charm and I am very happy to continue working effectively on my little project. I tried solving this bug for almost 3 weeks (not every day and only in the evening... but it went to be annoying). So a last time I have to say: thank you very much! – FatalDiskError Dec 22 '15 at 20:41