Is calling destructor manually always a sign of ba

2019-01-03 14:41发布

I was thinking: they say if you're calling destructor manually - you're doing something wrong. But is it always the case? Are there any counter-examples? Situations where it is neccessary to call it manually or where it is hard/impossible/impractical to avoid it?

13条回答
祖国的老花朵
2楼-- · 2019-01-03 15:07

Any time you need to separate allocation from initialization, you'll need placement new and explicit calling of the destructor manually. Today, it's rarely necessary, since we have the standard containers, but if you have to implement some new sort of container, you'll need it.

查看更多
女痞
3楼-- · 2019-01-03 15:07

I found 3 occasions where I needed to do this:

  • allocating/deallocating objects in memory created by memory-mapped-io or shared memory
  • when implementing a given C interface using C++ (yes this still happens today unfortunately (because I don't have enough clout to change it))
  • when implementing allocator classes
查看更多
叼着烟拽天下
4楼-- · 2019-01-03 15:11

All answers describe specific cases, but there is a general answer:

You call the dtor explicitly every time you need to just destroy the object (in C++ sense) without releasing the memory the object resides in.

This typically happens in all the situation where memory allocation / deallocation is managed independently from object construction / destruction. In those cases construction happens via placement new upon an existent chunk of memory, and destruction happens via explicit dtor call.

Here is the raw example:

{
  char buffer[sizeof(MyClass)];

  {
     MyClass* p = new(buffer)MyClass;
     p->dosomething();
     p->~MyClass();
  }
  {
     MyClass* p = new(buffer)MyClass;
     p->dosomething();
     p->~MyClass();
  }

}

Another notable example is the default std::allocator when used by std::vector: elements are constructed in vector during push_back, but the memory is allocated in chunks, so it pre-exist the element contruction. And hence, vector::erase must destroy the elements, but not necessarily it deallocates the memory (especially if new push_back have to happen soon...).

It is "bad design" in strict OOP sense (you should manage objects, not memory: the fact objects require memory is an "incident"), it is "good design" in "low level programming", or in cases where memory is not taken from the "free store" the default operator new buys in.

It is bad design if it happens randomly around the code, it is good design if it happens locally to classes specifically designed for that purpose.

查看更多
一夜七次
5楼-- · 2019-01-03 15:19

I have never come across a situation where one needs to call a destructor manually. I seem to remember even Stroustrup claims it is bad practice.

查看更多
smile是对你的礼貌
6楼-- · 2019-01-03 15:20

What about this?
Destructor is not called if an exception is thrown from the constructor, so I have to call it manually to destroy handles that have been created in the constructor before the exception.

class MyClass {
  HANDLE h1,h2;
  public:
  MyClass() {
    // handles have to be created first
    h1=SomeAPIToCreateA();
    h2=SomeAPIToCreateB();
    ...
    try {
      if(error) {
        throw MyException();
      }
    }
    catch(...) {
      this->~MyClass();
      throw;
    }
  }
  ~MyClass() {
    SomeAPIToDestroyA(h1);
    SomeAPIToDestroyB(h2);
  }
};
查看更多
Viruses.
7楼-- · 2019-01-03 15:23

As quoted by the FAQ, you should call the destructor explicitly when using placement new.

This is about the only time you ever explicitly call a destructor.

I agree though that this is seldom needed.

查看更多
登录 后发表回答