<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/">
	<channel>
		<title><![CDATA[MISRA Discussion Forums - 4.15 Special member functions]]></title>
		<link>https://forum.misra.org.uk/</link>
		<description><![CDATA[MISRA Discussion Forums - https://forum.misra.org.uk]]></description>
		<pubDate>Thu, 12 Nov 2026 17:04:43 +0000</pubDate>
		<generator>MyBB</generator>
		<item>
			<title><![CDATA[Rule 15.1.2]]></title>
			<link>https://forum.misra.org.uk/showthread.php?tid=1764</link>
			<pubDate>Thu, 19 Feb 2026 13:33:04 +0000</pubDate>
			<dc:creator><![CDATA[<a href="https://forum.misra.org.uk/member.php?action=profile&uid=6654">Merge</a>]]></dc:creator>
			<guid isPermaLink="false">https://forum.misra.org.uk/showthread.php?tid=1764</guid>
			<description><![CDATA[<span style="font-family: 'Open Sans', sans-serif;" class="mycode_font">Hi,</span><br />
<br />
<span style="font-family: 'Open Sans', sans-serif;" class="mycode_font">We are having a discussion internally about how to interpret rule 15.1.2. In particular, the rule exception says that a class is considered empty "when it has [...], no virtual member functions, [...]".<br />
The question is whether a virtual (defaulted) destructor is considered a virtual member function in this context. For example, whether the following class is considered empty or not for the sake of this rule:<br />
<br />
</span><br />
<div class="codeblock"><div class="title">Code:</div><div class="body" dir="ltr"><code>struct Base () {<br />
    virtual ~Base() = default;<br />
};</code></div></div><span style="font-family: 'Open Sans', sans-serif;" class="mycode_font"><br />
My personal interpretation is that this class is not considered empty (it will contain the v-table), so it does not qualify as an exception w.r.t. rule 15.2 when used as a base class. Can you confirm that this interpretation is correct?<br />
<br />
Thank you very much and b</span><span style="font-family: 'Open Sans', sans-serif;" class="mycode_font">est regards,</span><br />
<span style="font-family: 'Open Sans', sans-serif;" class="mycode_font">Daniel "Merge" Merget</span>]]></description>
			<content:encoded><![CDATA[<span style="font-family: 'Open Sans', sans-serif;" class="mycode_font">Hi,</span><br />
<br />
<span style="font-family: 'Open Sans', sans-serif;" class="mycode_font">We are having a discussion internally about how to interpret rule 15.1.2. In particular, the rule exception says that a class is considered empty "when it has [...], no virtual member functions, [...]".<br />
The question is whether a virtual (defaulted) destructor is considered a virtual member function in this context. For example, whether the following class is considered empty or not for the sake of this rule:<br />
<br />
</span><br />
<div class="codeblock"><div class="title">Code:</div><div class="body" dir="ltr"><code>struct Base () {<br />
    virtual ~Base() = default;<br />
};</code></div></div><span style="font-family: 'Open Sans', sans-serif;" class="mycode_font"><br />
My personal interpretation is that this class is not considered empty (it will contain the v-table), so it does not qualify as an exception w.r.t. rule 15.2 when used as a base class. Can you confirm that this interpretation is correct?<br />
<br />
Thank you very much and b</span><span style="font-family: 'Open Sans', sans-serif;" class="mycode_font">est regards,</span><br />
<span style="font-family: 'Open Sans', sans-serif;" class="mycode_font">Daniel "Merge" Merget</span>]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[15.1.4 potentially incomplete wording]]></title>
			<link>https://forum.misra.org.uk/showthread.php?tid=1762</link>
			<pubDate>Fri, 16 Jan 2026 13:09:53 +0000</pubDate>
			<dc:creator><![CDATA[<a href="https://forum.misra.org.uk/member.php?action=profile&uid=5889">hahn</a>]]></dc:creator>
			<guid isPermaLink="false">https://forum.misra.org.uk/showthread.php?tid=1762</guid>
			<description><![CDATA[Hi,<br />
<br />
For the following code, to the best of our knowledge, the C++ standard guarantees that m1 and m2 are both properly initialized when creating an object of type C ([class.base.init]p9 and [dcl.init]p7).<br />
<br />
<div class="codeblock"><div class="title">Code:</div><div class="body" dir="ltr"><code>class M { M() {} };<br />
class C {<br />
  M m1;<br />
  M m2[2];<br />
<br />
  C() {}<br />
};</code></div></div><br />
<br />
However, being strict with the amplification given for rule 15.1.4, data member m2 cannot be considered initialized: neither is C() delegating, nor does m2 have a default member initializer, nor does it appear in the member initialization list, nor does its (array) type feature a constructor.<br />
m1 is considered initialized as its type M has a constructor.<br />
<br />
We think the code example should be compliant, but the rule amplification wording seems incomplete.<br />
Can you confirm this interpretation or do we miss a reason for this code to be non-compliant w.r.t. 15.1.4?<br />
<br />
Thanks in advance!]]></description>
			<content:encoded><![CDATA[Hi,<br />
<br />
For the following code, to the best of our knowledge, the C++ standard guarantees that m1 and m2 are both properly initialized when creating an object of type C ([class.base.init]p9 and [dcl.init]p7).<br />
<br />
<div class="codeblock"><div class="title">Code:</div><div class="body" dir="ltr"><code>class M { M() {} };<br />
class C {<br />
  M m1;<br />
  M m2[2];<br />
<br />
  C() {}<br />
};</code></div></div><br />
<br />
However, being strict with the amplification given for rule 15.1.4, data member m2 cannot be considered initialized: neither is C() delegating, nor does m2 have a default member initializer, nor does it appear in the member initialization list, nor does its (array) type feature a constructor.<br />
m1 is considered initialized as its type M has a constructor.<br />
<br />
We think the code example should be compliant, but the rule amplification wording seems incomplete.<br />
Can you confirm this interpretation or do we miss a reason for this code to be non-compliant w.r.t. 15.1.4?<br />
<br />
Thanks in advance!]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Application of Rule 15.0.1 to Abstract Interface Classes]]></title>
			<link>https://forum.misra.org.uk/showthread.php?tid=1684</link>
			<pubDate>Tue, 14 May 2024 18:19:24 +0000</pubDate>
			<dc:creator><![CDATA[<a href="https://forum.misra.org.uk/member.php?action=profile&uid=6399">nehalpatel</a>]]></dc:creator>
			<guid isPermaLink="false">https://forum.misra.org.uk/showthread.php?tid=1684</guid>
			<description><![CDATA[It seems rule 15.0.1 has conflicting requirements for pure virtual / abstract classes with no data members. e.g. if we create the following classes:<br />
<br />
<div class="codeblock"><div class="title">Code:</div><div class="body" dir="ltr"><code>class CanMessage {<br />
public:<br />
  CanMessage();<br />
<br />
  // Required for inheritance<br />
  virtual ~CanMessage() = default;<br />
<br />
  // Want to move and copy through derived classes<br />
  CanMessage(const CanMessage&amp;) noexcept = default;<br />
  CanMessage(CanMessage&amp;&amp;) noexcept = default;<br />
  CanMessage&amp; operator=(const CanMessage&amp;) &amp; noexcept = default;<br />
  CanMessage&amp; operator=(CanMessage&amp;&amp;) &amp; noexcept = default;<br />
<br />
  virtual uint32_t Id() = 0;<br />
  virtual uint8_t DataLength() = 0;<br />
  virtual std::span&lt;std::byte&gt; Data() = 0;<br />
};<br />
<br />
class CanClassicMessage : public CanMessage {<br />
public:<br />
  CanClassicMessage(uint32_t id, uint8_t data_length) : CanMessage{}, id_{id} data_length_{data_length} {}<br />
  ~CanClassicMessage() noexcept override = default;<br />
<br />
  CanClassicMessage(const CanClassicMessage&amp;) noexcept = default;<br />
  CanClassicMessage(CanClassicMessage&amp;&amp;) noexcept = default;<br />
  CanClassicMessage&amp; operator=(const CanClassicMessage&amp;) &amp; noexcept = default;<br />
  CanClassicMessage&amp; operator=(CanClassicMessage&amp;&amp;) &amp; noexcept = default;<br />
<br />
  uint32_t Id() override { return id_; }<br />
  uint8_t DataLength() override { return data_length_; }<br />
  std::span&lt;std::byte&gt; Data() { return data_; }<br />
  <br />
private:<br />
  uint32_t id_;<br />
  uint8_t data_length_;<br />
  std::array&lt;std::byte, 8&gt; data_;<br />
};<br />
<br />
class CanFDMessage : public CanMessage {<br />
public:<br />
  CanFDMessage(uint32_t id, uint8_t data_length) : CanMessage{}, id_{id} data_length_{data_length} {}<br />
  ~CanFDMessage() noexcept override = default;<br />
<br />
  CanFDMessage(const CanFDMessage&amp;) noexcept = default;<br />
  CanFDMessage(CanFDMessage&amp;&amp;) noexcept = default;<br />
  CanFDMessage&amp; operator=(const CanFDMessage&amp;) &amp; noexcept = default;<br />
  CanFDMessage&amp; operator=(CanFDMessage&amp;&amp;) &amp; noexcept = default;<br />
<br />
  uint32_t Id() override { return id_; }<br />
  uint8_t DataLength() override { return data_length_; }<br />
  std::span&lt;std::byte&gt; Data() { return data_; }<br />
<br />
private:<br />
  uint32_t id_;<br />
  uint8_t data_length_;<br />
  std::array&lt;std::byte, 64&gt; data_;<br />
}</code></div></div><br />
Per the rule, we either need <ul class="mycode_list"><li>a protected non-virtual destructor.<br />
</li>
<li>Unmovable class that has a public virtual destructor.<br />
</li>
</ul>
<br />
However these prevent us from being able to create a std::unique_ptr to the base class (and allow the derived classes to manage their data through their destructors), or prevents us from being able to copy or move one CanClassicMessage to another CanClassicMessage, if the base copy/move constructors are deleted.<br />
<br />
There is an exception for Aggreagate types, but it seems there needs to be an other one for an Interface/Abstract class which holds no data.]]></description>
			<content:encoded><![CDATA[It seems rule 15.0.1 has conflicting requirements for pure virtual / abstract classes with no data members. e.g. if we create the following classes:<br />
<br />
<div class="codeblock"><div class="title">Code:</div><div class="body" dir="ltr"><code>class CanMessage {<br />
public:<br />
  CanMessage();<br />
<br />
  // Required for inheritance<br />
  virtual ~CanMessage() = default;<br />
<br />
  // Want to move and copy through derived classes<br />
  CanMessage(const CanMessage&amp;) noexcept = default;<br />
  CanMessage(CanMessage&amp;&amp;) noexcept = default;<br />
  CanMessage&amp; operator=(const CanMessage&amp;) &amp; noexcept = default;<br />
  CanMessage&amp; operator=(CanMessage&amp;&amp;) &amp; noexcept = default;<br />
<br />
  virtual uint32_t Id() = 0;<br />
  virtual uint8_t DataLength() = 0;<br />
  virtual std::span&lt;std::byte&gt; Data() = 0;<br />
};<br />
<br />
class CanClassicMessage : public CanMessage {<br />
public:<br />
  CanClassicMessage(uint32_t id, uint8_t data_length) : CanMessage{}, id_{id} data_length_{data_length} {}<br />
  ~CanClassicMessage() noexcept override = default;<br />
<br />
  CanClassicMessage(const CanClassicMessage&amp;) noexcept = default;<br />
  CanClassicMessage(CanClassicMessage&amp;&amp;) noexcept = default;<br />
  CanClassicMessage&amp; operator=(const CanClassicMessage&amp;) &amp; noexcept = default;<br />
  CanClassicMessage&amp; operator=(CanClassicMessage&amp;&amp;) &amp; noexcept = default;<br />
<br />
  uint32_t Id() override { return id_; }<br />
  uint8_t DataLength() override { return data_length_; }<br />
  std::span&lt;std::byte&gt; Data() { return data_; }<br />
  <br />
private:<br />
  uint32_t id_;<br />
  uint8_t data_length_;<br />
  std::array&lt;std::byte, 8&gt; data_;<br />
};<br />
<br />
class CanFDMessage : public CanMessage {<br />
public:<br />
  CanFDMessage(uint32_t id, uint8_t data_length) : CanMessage{}, id_{id} data_length_{data_length} {}<br />
  ~CanFDMessage() noexcept override = default;<br />
<br />
  CanFDMessage(const CanFDMessage&amp;) noexcept = default;<br />
  CanFDMessage(CanFDMessage&amp;&amp;) noexcept = default;<br />
  CanFDMessage&amp; operator=(const CanFDMessage&amp;) &amp; noexcept = default;<br />
  CanFDMessage&amp; operator=(CanFDMessage&amp;&amp;) &amp; noexcept = default;<br />
<br />
  uint32_t Id() override { return id_; }<br />
  uint8_t DataLength() override { return data_length_; }<br />
  std::span&lt;std::byte&gt; Data() { return data_; }<br />
<br />
private:<br />
  uint32_t id_;<br />
  uint8_t data_length_;<br />
  std::array&lt;std::byte, 64&gt; data_;<br />
}</code></div></div><br />
Per the rule, we either need <ul class="mycode_list"><li>a protected non-virtual destructor.<br />
</li>
<li>Unmovable class that has a public virtual destructor.<br />
</li>
</ul>
<br />
However these prevent us from being able to create a std::unique_ptr to the base class (and allow the derived classes to manage their data through their destructors), or prevents us from being able to copy or move one CanClassicMessage to another CanClassicMessage, if the base copy/move constructors are deleted.<br />
<br />
There is an exception for Aggreagate types, but it seems there needs to be an other one for an Interface/Abstract class which holds no data.]]></content:encoded>
		</item>
	</channel>
</rss>