0

Assume an object can be cited (or referenced) by other objects. Currently I use a member variable to record its citation count. The citation count is used to determine if the object can be deleted or not.

class Cited
{
public:
    int m_citationCount;
};

I make the variable public. When the object is cited, it is increased by 1. If it is uncited, it is decreased by 1. Making the variable public doesn't seem proper. If it has only one type of citer, I can make the citer type a friend. However, there may be all kinds of citers. Any better idea to do it?

More information: These objects are items or nodes in a tree structure. Some nodes may reference other nodes. For example, a node is called air which represents material air with its properties like density. A node called background may reference the air node to show the background is air. Operations on the tree are undoable. If a user deletes the background node, it is just pushed in an undo stack. It is not really deleted.

user1899020
  • 13,167
  • 21
  • 79
  • 154
  • 2
    By "citation", what do you mean? Is this some kind of academic resource indexing system or something like that? Or are you talking about ordinary reference-counting? You may want to look at [shared pointers](http://stackoverflow.com/questions/106508/what-is-a-smart-pointer-and-when-should-i-use-one). – user2357112 Jul 01 '14 at 03:42
  • 1
    It's a bad idea to expose `m_citationCount` as a public variable. At the least, control it with public functions -- `incrementCitationCount()` and `decrementCitationCount()` come to mind. – R Sahu Jul 01 '14 at 05:00
  • 1
    Better names would be `cite` and `uncite`. – Mike DeSimone Jul 01 '14 at 05:16
  • Have a look at [persistent tree data structure](http://en.wikipedia.org/wiki/Persistent_data_structure#Trees). – D Drmmr Jul 01 '14 at 07:14

2 Answers2

3

Save yourself the grief and just use C++'s shared_ptr template.


OK, now that the question has been changed, the answer needs to as well.

Basically, you just need to employ a few strategies:

Linking using shared_ptr

Any time you need to keep track of a node, use a shared_ptr<Node> where Node is your node class. For example, if a Node needs to refer to another Node, then it has a shared_ptr<Node> to do so. For exampleworking off your example, you could have:

class Material: public Node { // Material properties here };

class Background: public Node { // Material properties here void SetMaterial(shared_ptr mat); };

void set_stage() { shared_ptr air = new Material(/constructor parameters/); shared_ptr skyBG = new Background(/constructor parameters/); skyBG->SetMaterial(air); }

Undo support

To have undo support, remember that an undo stack is generally a stack of actions, and each action contains enough information to figure out what was done (so it can be undone). If an action involves a node, then it should (like everything else) use a shared_ptr<Node> to refer to it.

Mike DeSimone
  • 41,631
  • 10
  • 72
  • 96
  • Those cited objects and citers are in fact undoable which are not really deleted. Thus, shared_ptr may not be used. – user1899020 Jul 01 '14 at 04:01
  • 1
    @user1899020 with the addition of this comment, I'm having a _really hard_ time understanding the problem you're solving. What is "in fact undoable"? It now sounds like you're adding `weak_ptr` to the problem. – Drew Dormann Jul 01 '14 at 04:04
  • @DrewDormann These objects are items or nodes in a tree structure. Some nodes may reference other nodes. For example, a node is called air which represents material air with its properties like density. A node called background may reference the air node to show the background is air. Operations on the tree are undoable. If a user deletes the background node, it is just pushed in an undo stack. It is not really deleted. – user1899020 Jul 01 '14 at 04:12
  • @user1899020: I'm not sure what you're trying to convey, but you may be interested to know that `shared_ptr` allows you to specify a custom deleter. That might solve some of your problems. – user2357112 Jul 01 '14 at 04:21
  • 2
    @user1899020: Ok, then stick a `shared_ptr` in the undo stack, which will keep it alive. – Ben Voigt Jul 01 '14 at 04:32
1

You could potentially work out a scheme using a shared_ptr with a custom deleter that would do whatever you need it to when the count drops to zero.

Or you could roll something manually. At a minimum it would probably be a good idea to make the count variable private and provided public methods to do the work:

class Cited
{
public:
    void CreateCitation()
    {
        ++m_citationCount;
    }

    void RemoveCitation()
    {
        --m_citationCount;

        if(m_citationCount == 0)
        {
            // ... whatever special logic happens at zero.
        }
    }

private:
    int m_citationCount;
};

But that could be taken further by creating a Citation class to act rather like a smart pointer. Such a class would be returned by CreateCitation, would keep a pointer to the Cited object, and would call RemoveCitation in its destructor.

For example:

class Citation
{
public:
    Citation(Cited* c) : m_cited(c) {}

    ~Citation()
    {
        m_cited->RemoveCitation();
    }

    // ... whatever else to make this more usable.

    Cited* m_cited;
};

Those are just the basic ideas. There's various aspects that would need to be polished up (such as dealing with the Citation class's copy constructor and assignment operator).

TheUndeadFish
  • 8,058
  • 1
  • 23
  • 17