Does explicitly calling destructor result in Undef

2020-02-06 09:00发布

In my opinion, the following code (from some C++ question) should lead to UB, but the it seems it is not. Here is the code:

#include <iostream>
using namespace std;
class some{ public: ~some() { cout<<"some's destructor"<<endl; } };
int main() { some s; s.~some(); }

and the answer is:

some's destructor
some's destructor

I learned form c++ faq lite that we should not explicitly call destructor. I think after the explicitly call to the destructor, the object s should be deleted. The program automatically calls the destructor again when it's finished, it should be UB. However, I tried it on g++, and get the same result as the above answer.

Is it because the class is too simple (no new/delete involved)? Or it's not UB at all in this case?

9条回答
女痞
2楼-- · 2020-02-06 09:12

From http://www.devx.com/tips/Tip/12684

Undefined behavior indicates that an implementation may behave unpredictably when a program reaches a certain state, which almost without exception is a result of a bug. Undefined behavior can be manifested as a run time crash, unstable and unreliable program state, or--in rare cases--it may even pass unnoticed.

In your case it doesn't crash because the destructor doesn't manipulate any field; actually, your class doesn't have any data members at all. If it did and in destructor's body you manipulated it in any way, you would likely get a run-time exception while calling destructor for the second time.

查看更多
forever°为你锁心
3楼-- · 2020-02-06 09:20

The problem here is that deletion / deallocation and destructors are separate and independent constructs. Much like new / allocation and constructors. It is possible to do only one of the above without the other.

In the general case this scenario does lack usefulness and just lead to confusion with stack allocated values. Off the top of my head I can't think of a good scenario where you would want to do this (although I'm sure there is potentially one). However it is possible to think of contrived scenarios where this would be legal.

class StackPointer<T> {
  T* m_pData;
public:
  StackPointer(T* pData) :m_pData(pData) {}
  ~StackPointer() { 
    delete m_pData; 
    m_pData = NULL; 
  }
  StackPointer& operator=(T* pOther) {
    this->~StackPointer();
    m_pData = pOther;
    return this;
  }
};

Note: Please don't ever code a class this way. Have an explicit Release method instead.

查看更多
对你真心纯属浪费
4楼-- · 2020-02-06 09:21

It most likely works fine because the destructor does not reference any class member variables. If you tried to delete a variable within the destructor you would probably run into trouble when it is automatically called the second time.

Then again, with undefined behavior, who knows? :)

查看更多
够拽才男人
5楼-- · 2020-02-06 09:25

Can you define the undefined behaviour you expect? Undefined doesn't mean random (or catastrophic): the behaviour of a given program may be repeatable between invocations, it just means you can't RELY on any particular behaviour because it is undefined and there is no guarantee of what will happen.

查看更多
可以哭但决不认输i
6楼-- · 2020-02-06 09:25

It is undefined behaviour. The undefined behaviour is the double destructor call and not with the destructor call itself. If you modify your example to:

#include <iostream>
using namespace std;
class some{ public: ~some() { [INSERT ANY CODE HERE] } };
int main() { some s; s.~some(); }

where [INSERT ANY CODE HERE] can be replaced with any arbitrary code. The results have unpredictable side effects, which is why it is considered undefined.

查看更多
甜甜的少女心
7楼-- · 2020-02-06 09:26

It's undefined behavior -- but as with any UB, one possibility is that it (more or less) appears to work, at least for some definition of work.

Essentially the only time you need (or want) to explicitly invoke a destructor is in conjunction with placement new (i.e., you use placement new to create an object at a specified location, and an explicit dtor invocation to destroy that object).

查看更多
登录 后发表回答