Using std vector of custom c++ class pointer


#1

Hi,

I am trying to see what is it possible to do with chaiscript in order to integrate it into our project.

I made a little example to learn how to use it and I have a problem with the use of std::vector, here is my code snippet :

#include <chaiscript/chaiscript.hpp>
#include <chaiscript/utility/utility.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>

// Basic graph class
class MyGraph
{
public:
    MyGraph(const std::string& nom = std::string())
    {
        pParent_ = nullptr;
        name_ = nom;
    }

    ~MyGraph()
    {
    }

    void SetNom(const std::string& n)
    {
        name_ = n;
    }

    std::string GetNom() const
    {
        return name_;
    }

    void AjouterFils(MyGraph* fils)
    {
        listChild_.push_back(fils);
        fils->pParent_ = this;
    }

    const std::vector<MyGraph*>& GetListChild() const
    {
        return listChild_;
    }

    std::string to_string()
    {
        std::string name;

        MyGraph* pThis = this;
        while (pThis != nullptr)
        {
            name += pThis->name_ + " -> ";

            pThis = pThis->pParent_;
        }

        return name;
    }

private:
    std::string             name_;
    MyGraph*                pParent_;
    std::vector<MyGraph*>   listChild_;
};

// Scene graph init
MyGraph* InitGraph()
{
    MyGraph* root = new MyGraph("root");

    // niveau 1
    MyGraph* fils1 = new MyGraph("fils1");
    root->AjouterFils(fils1);
    MyGraph* fils2 = new MyGraph("fils2");
    root->AjouterFils(fils2);
    MyGraph* fils3 = new MyGraph("fils3");
    root->AjouterFils(fils3);

    // niveau 2
    MyGraph* fils11 = new MyGraph("fils11");
    fils1->AjouterFils(fils11);
    MyGraph* fils12 = new MyGraph("fils12");
    fils1->AjouterFils(fils12);
    MyGraph* fils31 = new MyGraph("fils31");
    fils3->AjouterFils(fils31);

    return root;

}

static MyGraph* pRoot_ = nullptr;

// Return every node that match with the name
std::vector<MyGraph*> GetNodesVec(const std::string& nodeName)
{
    std::vector<MyGraph*> resultats;
    std::function<void(MyGraph*)> Parcour;
    Parcour = [&resultats, nodeName, &Parcour](MyGraph * graph)
    {
        if (graph->GetNom() == nodeName)
        {
            resultats.push_back(graph);
        }
        for (unsigned int i = 0; i < graph->GetListChild().size(); ++i)
        {
            Parcour(graph->GetListChild()[i]);
        }
    };

    Parcour(pRoot_);

    return resultats;
}

// Return one node that match with the name
MyGraph* GetNode(const std::string& nodeName)
{
    std::function<MyGraph*(MyGraph*)> Parcour;
    Parcour = [nodeName, &Parcour](MyGraph * graph) -> MyGraph*
    {
        if (graph->GetNom() == nodeName)
        {
            return graph;
        }
        for (unsigned int i = 0; i < graph->GetListChild().size(); ++i)
        {
            MyGraph* ptr = Parcour(graph->GetListChild()[i]);
            if (ptr != nullptr)
                return ptr;
        }
        return nullptr;
    };

    return Parcour(pRoot_);
}

int main(int ac, char** av)
{
    pRoot_ = InitGraph();
    chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());

    chai.add(chaiscript::bootstrap::standard_library::vector_type<std::vector<MyGraph*>>("VecMyGraph"));

    chai.add(chaiscript::fun(&GetNode), "GetNode");
    chai.add(chaiscript::fun(&GetNodesVec), "GetNodesVec");

    chai.add(chaiscript::user_type<MyGraph>(), "MyGraph");
    chai.add(chaiscript::fun(&MyGraph::to_string), "to_string");

    chai.add(chaiscript::var(pRoot_), "root");

    std::string line;

    while (true)
    {
        std::cin >> line;

        try
        {
            chai.eval(line);
        }
        catch (std::exception e)
        {
            std::cout << "ERROR : " << e.what() << std::endl;
        }

    }
}

The problem is, when I use
print(GetNode("fils31").to_string)
everything works fine

But when I use :
print(GetNodesVec("fils31").front.to_string)
it crashes inside to_string method because this pointer is dirty…

What am I doing wrong ?

Thank you !


#2

By going two levels deep with your . function calls you have uncovered a parser bug that I was not previously aware of. The value returned from GetNodesVec("fils31").front() is being popped from the stack before to_string() can be called.

I’ll try to fix it as soon as I can. In the meantime, doing just about anything else would work:

print(to_string(front(GetNodesVec("fils31"))));`
print("${GetNodesVec("fils31").front()}")
var value = GetNodesVec("fils31").front();
print(value.to_string);

On the upside, I believe if I fix this parsing to make sure . is fully left-associative, then I should be able to clean up some other code.


#3

Ok thank !

I have to said that I am very impressed about the powerfulness of your library… Congrats !


#4

Actually, seems I was wrong, something else is going on that I don’t quite understand. I’ll get back to you shortly.

-Jason


#5

Ok, I figured it out. It’s because std::vector<Node *>::front returns a reference to a pointer, which isn’t something I was handling properly internally.

I’ve tagged v5.8.3 that fixes that use case. https://github.com/ChaiScript/ChaiScript/releases/tag/v5.8.3

-Jason