{"id":103877,"date":"2020-06-19T07:00:00","date_gmt":"2020-06-19T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=103877"},"modified":"2020-06-19T06:41:40","modified_gmt":"2020-06-19T13:41:40","slug":"20200619-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200619-00\/?p=103877","title":{"rendered":"Understanding warning C4265: class has virtual functions, but destructor is not virtual, part 2"},"content":{"rendered":"<p><a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200618-00\/?p=103874\"> Last time<\/a>, we learned about what warning C4265 (class has virtual functions, but destructor is not virtual) is trying to say. The fact that it warns you even in the absence of a suspicious <code>delete<\/code> means that you can get quite a lot of false positives.<\/p>\n<pre>struct Interface\r\n{\r\n    virtual void f() = 0;\r\n    virtual void Destroy() = 0;\r\n};\r\n\r\nstruct Implementation : Interface\r\n{\r\n    ~Implementation();\r\n    void f() override;\r\n    void Destroy() override;\r\n};\r\n<\/pre>\n<p>This triggers the warning because <code>Implementation<\/code> has a non-virtual destructor and virtual methods <code>f<\/code> and <code>Destroy<\/code>.<\/p>\n<p>What the compiler doesn&#8217;t realize is that the <code>Destroy<\/code> method is how the object is destructed. And the <code>Destroy<\/code> method is virtual, so everything is just fine. It doesn&#8217;t realize this even if you make the <code>~Implementation()<\/code> destructor protected or private.<\/p>\n<p>This pattern is common when implementing COM interfaces, where <code>Release<\/code> acts as the virtual destructor-ish method.<\/p>\n<pre>struct Thing : public IThing\r\n{\r\n  \/\/ IUnknown\r\n  HRESULT QueryInterface(REFIID riid, void** ppv) override;\r\n\r\n  ULONG AddRef() override { return ++m_refCount; }\r\n\r\n  ULONG Release() override\r\n  {\r\n    auto refCount = --m_refCount;\r\n    if (refCount == 0) delete this;\r\n    return refCount;\r\n  }\r\n\r\n  \/\/ IThing\r\n  HRESULT <a href=\"https:\/\/www.amazon.com\/DoTheThing-Because-comfort-zones-boring\/dp\/0996731121\">DoTheThing<\/a>() override;\r\n\r\nprivate:\r\n  ~Thing();\r\n  std::atomic_ulong m_refCount = 1;\r\n};\r\n<\/pre>\n<p>This is pretty standard boilerplate for a COM object. The object&#8217;s destructor is private because you are expected to destruct the object by calling <code>Release<\/code>, rather than calling <code>delete<\/code>. But it also generates a spurious warning C4265.<\/p>\n<p>You can make the warning go away by declaring <code>Thing<\/code> as <code>final<\/code>.<\/p>\n<p>But there are cases where you have a class that is meant to be a base class, so you don&#8217;t want to mark it as <code>final<\/code>. If you&#8217;re using C++\/WinRT, you get to choose whether your implementation classes are final or not, and maybe you don&#8217;t want them to be final, but you do need them to be COM objects, and when you do, warning C4265 will spuriously appear.<\/p>\n<p>In WRL, an example of a non-final object with virtual methods is the <code>FtmBase<\/code>. This is a base class that implements <code>IMarshal<\/code> by forwarding all methods to the standard COM free-threade marshaler, thereby making your object free-threaded. (If you don&#8217;t know what this means, don&#8217;t worry. It&#8217;s not important to the main point of this article, though it&#8217;s a good thing to understand when you&#8217;re working with COM.)<\/p>\n<p>The point of the <code>FtmBase<\/code> is to be a base class for other COM objects. And when you do that, it is the <code>Release<\/code> method that triggers the destruction. Since <code>Release<\/code> is a virtual method, the <code>FtmBase::Release<\/code> will go to the most-derived object, and that implementation will perform the <code>delete<\/code> on the most-derived object, and everything will be fine.<\/p>\n<p>But the compiler doesn&#8217;t know that.<\/p>\n<p>The compiler sees a class like <code>FtmBase<\/code> that has the potential for being used incorrectly. If somebody did, say,<\/p>\n<pre>class Weird : public FtmBase\r\n{\r\n};\r\n\r\nvoid bad_idea()\r\n{\r\n  FtmBase* p = new Weird; \/\/ bad idea\r\n  delete p; \/\/ even worse idea\r\n}\r\n<\/pre>\n<p>they would stumble across the problem that warning C4265 is trying to tell you about.<\/p>\n<p>But nobody should be writing code like that in the first place. WRL objects should be created with <code>Make<\/code>, and C++\/WinRT objects should be created with <code>make<\/code>. In both cases, the object lifetimes are managed by <code>IUnknown<\/code>, which means that you <code>Release<\/code> the object when you&#8217;re done. The smart pointer classes in WRL and C++\/WinRT take care of this for you (similarly to <code>std::shared_ptr<\/code>), so you rarely see an explicit call to <code>Release<\/code>.<\/p>\n<p>In C++\/WinRT, the implementation template classes use CRTP, and the <code>Release<\/code> methods cast the <code>this<\/code> pointer to the most-derived type (the first template type parameter) before deleting, thereby accomplishing the same result in a different way.<\/p>\n<p>So yes, if you use WRL or C++\/WinRT, or more generally COM, you will see false positives of warning C4265. That may be one reason why warning C4265 is off by default.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Applying what we&#8217;ve learned.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-103877","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Applying what we&#8217;ve learned.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103877","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=103877"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103877\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=103877"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=103877"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=103877"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}