开发者

Will the following cause problems with memory?

Say I have the following in a DLL implementation (eg, it would have a cpp file):

class Base
{
protected:
    Something *some;
public:
    virtual void init()
    {开发者_如何转开发
        some = new Something();
    }

    virtual  ~Base()
    {
        delete some;
    }

};

Then in my exe I make:

class Derived : public Base
{
public:
    virtual void init()
    {
        some = new SomethingElse();
    }
};

int main()
{
   Base *blah = new Derived;
   delete blah;
}

Would this ever cause problems if the DLL is ran with a different runtime than the exe?

if so, is there a non boost, non c++ 0x solution

Thanks


I think you need to write ~Derive() like this

~Derived()
{
   delete some;
   some = 0; //this is must; so that `delete some` in ~Base() works perfectly; 
  //note `delete (void*)0` is fine in C++!
}

Explanation :

Why you need to write this even though the ~Base() does the same thing (it looks it does the same thing) is because ~Derived() ensures that you delete your object from the same heap/memory-pool/etc they were created on.

See these topics:

How to use a class in DLL?
Memory Management with returning char* function


EDIT:

Better would be to add one more virtual function, say deinit(), (a counter-part of your virtual void init()) , redefine this too when you redefine init(), and do the de-allocation there in deinit().

//DLL
class Base
{
protected:
    Something *some;
public:
    virtual void init()
    {
        some = new Something();
    }
    virtual void deinit()
    {
        delete some;
    }
    virtual  ~Base() { deinit(); }
};

//EXE
class Derived : public Base
{
public:
    virtual void init()
    {
        some = new SomethingElse();
    }
    virtual void deinit()
    {
        delete some; //some=0 is not needed anymore!
    }
};


Derived allocated some, thus it maintains the responsibility to deallocate it. Overwrite the destructor...

If you always follow that principle, then your memory handling is much simpler.


There won't be any problems, though obviously the code contained in Derived won't ever make it across to the other executable.

The destructor for Base will correctly delete some provided Something derives from SomethingElse and has a virtual destructor.


I think you should initialize something in its constructor.

Otherwise the destructor will delete a random piece of memory.

Base::Base()
    : Something(NULL)
{ } 


It's ugly code because of the protected variable.

I propose we reshape it up. First, let's make sure that all the ownership logic is insulated, so that it is easier to prove right.

class Base
{
public:
  Base(): some(0) {} // better initialize it...
  virtual ~Base() { delete some; }

  void init() { delete some; some = this->initImpl(); }

private:
  Base(Base const&); // no copy
  Base& operator=(Base const&); // no assignment

  virtual SomeType* initImpl() { return new SomeType(); }

  SomeType* some;
}; // class Base


class Derived: public Base
{
  virtual SomeOtherType* initImpl() { return new SomeOtherType(); }
};

It's only a first step though, because you should not try to manipulate resources directly, you're only going to leak them. So now, we take our shiny interface and reshape the implementation:

// something that you should definitely have for your base classes
class noncopyable { protected: noncopyable() {} private: noncopyable(noncopyable const&); noncopyable& operator=(noncopyable const&); };

class Base: noncopyable
{
public:
  Base() {}
  virtual ~Base() {}

  void init() { some.reset(this->initImpl()); }

private:
  virtual SomeType* initImpl() { return new SomeType(); }

  std::auto_ptr<SomeType> some;
}; // class Base

// same Derived class, that's the beauty of insulation :)

Isn't it much better ?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜