tags:

views:

109

answers:

2

I'm writing a program in python that uses genetic techniques to optimize expressions.

Constructing and evaluating the expression tree is the time consumer as it can happen

billions of times per run. So I thought I'd learn enough c++ to write it and then incorporate it

in python using cython or ctypes.

I've done some searching on stackoverflow and learned a lot.

This code compiles, but leaves the pointers dangling.

I tried this_node = new Node(... . It didn't seem to work. And I'm not at all sure how I'd

delete all the references as there would be hundreds.

I'd like to use variables that stay in scope, but maybe that's not the c++ way.

What is the c++ way?

    class Node
    {
    public:
        char *cargo;
        int depth;
        Node *left;
        Node *right;
    }


  Node make_tree(int depth)
    {
        depth--;   
        if(depth <= 0)
        {
            Node tthis_node("value",depth,NULL,NULL);
            return tthis_node;
        }
        else
        {
            Node this_node("operator" depth, &make_tree(depth), &make_tree(depth));
            return this_node;
        }

    };
+3  A: 

The C++ way would be to use smart pointers.

Here you're returning copies of local objects, making temporary objects. Once the make_node call is finished the object don't exist anymore making your pointers dangling. So don't do that.

Use smart pointers instead to allow the nodes to be freed once unreferenced.

Klaim
Would using smart pointers have a speed cost?
Peter Stewart
I would say "negligeable", it cost you more memory than speed. On the speed size it's almost like a raw pointer (assuming memver function calls are inlined). But just take a look at that doc from the boost::shared_ptr documentation : http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/smarttests.htm
Klaim
An interesting document, thanks for your reply.
Peter Stewart
+4  A: 

The Node object returned by make_tree() is just a temporary object, it will automatically be destroyed again at the end of the expression in which the function is called. When you create a pointer to such a temporary object, like in &make_tree(depth), this pointer will not point to anything useful anymore once the temporary object got destroyed.

You should use real dynamic memory allocation with new and delete to build the tree, so that you don't end up with pointers to not longer existing objects. Probably this construction of the tree should be done in a constructor of the Node class, the destructor should then take care of the deletes needed to release the used memory. For example:

class Node {
public:
    const char *cargo;
    int depth;
    Node *left;
    Node *right;

    Node(int a_depth);
    ~Node();
};

// constructor
Node::Node(int a_depth) {
    depth = a_depth;
    a_depth--;   
    if(a_depth <= 0)
    {
        cargo = "value";
        left = NULL;
        right = NULL;
    }
    else
    {
        cargo = "operator";
        left = new Node(a_depth);
        right = new Node(a_depth);
    }
}

// destructor
Node::~Node() {
    delete left;
    delete right;
}
sth
Yes, this makes a lot of sense to me, thanks.
Peter Stewart