views:

46

answers:

2

There is a member function which I would like to delete the current object and create an array of new ones in its place. How is it possible? The following code is an attempt of mine which has a lot of mistakes.

void LernaeanHydra::split(int parts)
{
    LernaeanHydra *new_heads = new LernaeanHydra[parts];
    for (int i = 0; i < parts; i++) {
        std::vector<LernaeanHydra *> child123;
        for (int j = i * parts; j < (i + 1) * parts; j++) {
            child123[j] = children[i * parts + j];
        }
        new_heads[i] = LernaeanHydra(child123, num_children/parts);
    }

    delete this;
}

I have read that we should never call explicitly the destructor and we should not attempt a delete this.

+1  A: 

Perhaps you need a dummy node which is initialized with a member of your node, then it can handle the split function properly:

Class Node {
public:
  Node() {
    obj = new Obj();
    issplit = false;
  }
  ~Node() {
    if (issplit) delete [] obj; else delete obj;
  }
  void split(int p) {
    if (!issplit) {
      delete obj;
      obj = new Obj[p];
    }
  }
private:
  Obj* obj;
  bool issplit;
}
Alexander Rafferty
+2  A: 

When you're splitting a node in a tree, you'd normally start with one node containing a vector of pointers to its child nodes. You'd then create one new node containing a vector of pointers to its child nodes that you'd initialized with half the child pointers from the current node. Afterwards, you erase those pointers from the current node -- but you certainly don't destroy it (even after "giving away" half its data, it still retains a fair amount that you don't want to throw away).

class Node { 
    // for the moment I'm ignoring the keys, though they'd also be needed for any
    // of this to accomplish much.
    std:vector<Node *> children;
    typedef std::vector<Node *>::iterator child_it;
public:
    Node(child_it begin, child_it end) : children(begin, end) {}

    Node *split() {
        size_t center = children.size() / 2;

        Node *new_node = new Node(children.begin()+center, children.end());
        children.erase(children.begin() + center, children.end());
        return new_node;
    }
};

Note that in C++0x, you'd probably want to move the pointers instead of copying then destroying the originals (though given that they are pointers, it probably won't make any real difference).

Also note that this should be exception safe -- if allocating/initializing the new node fails, the throw will prevent the children.erase from executing, so the node will remain exactly as it was before. We only erase the extra pointers after we've assured that creating the new node and copying them to it has succeeded.

Jerry Coffin