newbie -- smart pointer destructor called without destructor everbeing called

Discussion in 'C++' started by Jimmy Hartzell, May 19, 2008.

  1. I'm almost entirely new to C++, and so I assume I'm making a very common
    blunder.

    Context: I have an interpreted programming language with an interpreter
    written in C (which works rather well), where we wanted to replace the
    garbage collector we were using with one of our own, based off of
    reference counting and cycle checking. After some experimentation, we
    determined that it would be much more type-safe and easy-to-program in
    if we moved the project over to C++ and used smart pointers to enforce
    our invariants. Having little-to-know experience in C++, I decided to
    experiment with reference-counting smart pointers and see if I could get
    my own implementation to work.

    I wrote a test program to test the implementation, and I got a
    segmentation fault from my operating system. Inserting some debugging
    code (the member variable "sentinal" and the "assert" statement), I
    determined that it appears that, at some point, the software is
    destructing a GCReference that it never constructed.

    My implementation and test program follow:

    #include <cassert>
    #include <vector>

    using namespace std;

    class GCAllocation {
    int refcount;

    public:
    void ref() {
    __sync_fetch_and_add(&refcount,1);
    }

    void deref() {
    assert(refcount!=0);
    __sync_fetch_and_sub(&refcount,1);
    if(!refcount) {
    delete this;
    }
    }

    GCAllocation() : refcount(0) {
    refcount = 0;
    }

    virtual ~GCAllocation() {
    }
    };

    template<class T>
    class GCReference {
    T *referand;
    int sentinal;

    void do_ref() {
    if(referand) {
    referand->ref();
    }
    }

    void do_deref() {
    do_deref(referand);
    }

    void do_deref(T *referand) {
    if(referand) {
    referand->deref();
    }
    }

    public:
    GCReference(T *const referand = 0) {
    this->referand = referand;
    sentinal = 3133;
    do_ref();
    }

    GCReference(const GCReference<T> &ref) {
    referand = ref.referand;
    sentinal = 3133;
    do_ref();
    }

    ~GCReference() {
    assert(sentinal==3133);
    do_deref();
    }

    GCReference operator=(const GCReference<T>& ref) {
    // not thread-safe
    T* const old_ref = ref.referand;
    referand = ref.referand;

    // order necessary in case of self-assignment
    do_ref();
    do_deref(old_ref);
    }

    bool operator==(const GCReference<T>& ref) const {
    return referand == ref.referand;
    }

    operator bool() const {
    return referand;
    }

    T& operator*() const {
    return *referand;
    }

    T* operator->() const {
    return referand;
    }

    // not a cast, since that could be used by accident.
    // this should only be used when absolutely necessary.
    // TODO: find out how to support dynamic-casts without this
    // sort of mechanism
    T* get_raw_pointer() const {
    return referand;
    }
    };

    class GCTest: public virtual GCAllocation {
    public:
    vector<GCReference<GCTest> > refs;
    GCTest() {
    for(int i = 0; i < 16; ++i) {
    refs.push_back(0);
    }
    }

    void fill_all(GCReference<GCTest> what_with) {
    for(int i = 0; i < 16; ++i) {
    refs = what_with;
    }
    }
    };

    static void test() {
    GCReference<GCTest> test1(new GCTest());
    GCReference<GCTest> test2(new GCTest());
    test1->fill_all(test2);
    test1->fill_all(0);
    test1->fill_all(test2);
    test1->fill_all(0);
    assert(!test1->refs[5]);
    test1->fill_all(test2);
    assert(test1->refs[5] == test2);
    }

    int main() {
    while(1) {
    test();
    }
    return 0;
    }

    I get the following output:
    $ c++ simple.c++
    $ ./a.out
    a.out: simple.c++:65: GCReference<T>::~GCReference() [with T = GCTest]:
    Assertion `sentinal==3133' failed.
    $ c++ --versionc++ (GCC) 4.1.3 20070929 (prerelease) (Ubuntu
    4.1.2-16ubuntu2)
    Copyright (C) 2006 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions. There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

    $
     
    Jimmy Hartzell, May 19, 2008
    #1
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    0
    Views:
    433
  2. coala
    Replies:
    3
    Views:
    414
    coala
    Sep 6, 2006
  3. coala
    Replies:
    1
    Views:
    614
    Victor Bazarov
    Sep 6, 2006
  4. Jimmy Hartzell
    Replies:
    2
    Views:
    1,184
    Jimmy Hartzell
    May 20, 2008
  5. Hicham Mouline
    Replies:
    100
    Views:
    2,148
    Noah Roberts
    Aug 25, 2009
Loading...

Share This Page