Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
174 views
in Technique[技术] by (71.8m points)

c++ - delete via a pointer to Derived, not Base

I implemented a basic Smart pointer class. It works for the following type of code. (considering Base1 has a public constructor)

Sptr<Base1> b(new Base1);
b->myFunc();
{
    Sptr<Base1> c = b;
    Sptr<Base1> d(b);
    Sptr<Base1> e;
    e = b;
}

But in the test code it has a protected constructor(I need it to be this way). and the code

Sptr<Base1> sp(new Derived);

Produces the following error (notice the Derived):

Sptr.cpp: In instantiation of ‘my::Sptr<T>::~Sptr() [with T = Base1]’:
Sptr.cpp:254:39:   required from here
Sptr.cpp:205:9: error: ‘Base1::~Base1()’ is protected
Sptr.cpp:97:17: error: within this context

The problem is I have to Make sure that you delete via a pointer to Derived, not Base1. How can I do that?

Here is the class code (clipped to show constructor and distructor and class members)

template <class T>
class Sptr {
private:
   T* obj; // The actual object pointed by
       RC* ref;// A reference object to keep track of count
public:
  //declarations


template <typename T>
Sptr<T>::Sptr():obj(NULL),ref(NULL) {
    //do something
    std::cout<<"()
";
    ref = new RC();
    ref->AddRef();
}

template <typename T>
Sptr<T>::Sptr(const Sptr &a) : obj(a.obj),ref(a.ref) {
    //do something
    std::cout<<"const Sptr
";
    ref->AddRef();
}

template <typename T>
Sptr<T>::~Sptr() {
    //do something
    if(ref->Release() == 0) {
        if(obj)
            delete obj;

        delete ref;
    }
}

template <typename T>
template <typename U>
Sptr<T>::Sptr(U* u) : obj(u),ref(NULL) {
    //do something
    ref = new RC();
    ref->AddRef();
}

template <typename T>
template <typename U> 
Sptr<T>::Sptr(const Sptr<U> &u) : obj(u.obj),ref(u.ref) {
    std::cout<<"const Sptr<U>
";
    ref->AddRef();
}

EDIT

The destructor is not virtual. That is the case I have to solve. Below is the Base1 and Derived classes

class Base1 {
    protected:
        Base1() : derived_destructor_called(false) {
            printf("Base1::Base1()
");
        }
    private:
        Base1(const Base1 &); // Disallow.
        Base1 &operator=(const Base1 &); // Disallow.
    protected:
        ~Base1() {
            printf("Base1::~Base1()
");
            assert(derived_destructor_called);
        }
    protected:
        bool derived_destructor_called;
};

class Derived : public Base1 {
        friend void basic_tests_1();
    private:
        Derived() {}
        Derived(const Derived &); // Disallow.
        Derived &operator=(const Derived &); // Disallow.
    public:
        ~Derived() {
            printf("Derived::~Derived()
");
            derived_destructor_called = true;
        }
        int value;
};
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If you make your constructor a template, you can detect the type of pointer passed in at construction time and save that information in your smart pointer (for example, in a polymorphic deleter object). This is (I believe) how shared_ptr<> does it. You can probably also use SFINAE to produce a compiler error if a pointer type is passed in that doesn't have an accessible destructor.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...