Make GxEPD2_Multi non-copyable to address cppcheck warnings (#11326)

cppcheck reports noCopyConstructor and noOperatorEq against GxEPD2_Multi
on every e-ink environment (over 80 duplicate pairs on a single
heltec-wireless-paper run, one per template instantiation point):

  src/graphics/GxEPD2Multi.h:123: [medium:warning] Class 'GxEPD2_Multi <
  GxEPD2_213_FC1 , GxEPD2_213_E0213A367 >' does not have a copy
  constructor which is recommended since it has dynamic memory/resource
  allocation(s). [noCopyConstructor]

The warning is correct. The constructor news one of two GxEPD2_BW drivers
into a raw pointer member and caches &driver->epd2 in epd2.m_epd2, so the
compiler-generated copy operations would alias that driver: two objects
would drive the same panel, and the second to be destroyed would free a
driver the first still points at.

Nothing copies it - EInkDisplay2 heap-allocates a single instance and
holds a pointer - so declare that intent by deleting the copy operations
rather than adding a suppression.

Also null the unselected driver pointer. Only one of driver0/driver1 is
allocated and the other was left indeterminate; every method branches on
`which` before dereferencing, so this is latent rather than a live bug,
but an indeterminate owning pointer is one refactor away from a wild
dereference.

Behaviour is unchanged: no caller could have copied this type, and the
two added stores only initialize a pointer that is never read.

Verified on heltec-wireless-paper: `./bin/check-all.sh
heltec-wireless-paper` now reports "No defects found" (exit 0), and
`pio run -e heltec-wireless-paper` builds clean. The build matters
separately here because syntaxError is suppressed in suppressions.txt,
so cppcheck alone would stay green on a malformed declaration.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Austin
2026-08-01 18:13:20 +00:00
committed by GitHub
co-authored by Claude Opus 5
parent d9f1622ec1
commit f481585de4
1 file changed
+9
+9
View File
@@ -115,6 +115,10 @@ template <typename Driver0, typename Driver1> class GxEPD2_Multi
// Select driver by passing whichDriver as 0 or 1
GxEPD2_Multi(uint8_t whichDriver, int16_t cs, int16_t dc, int16_t rst, int16_t busy, SPIClass &spi)
{
// Only the selected driver is allocated; the other stays null
driver0 = nullptr;
driver1 = nullptr;
assert(whichDriver == 0 || whichDriver == 1);
which = whichDriver;
LOG_DEBUG("GxEPD2_Multi driver: %d", which);
@@ -128,6 +132,11 @@ template <typename Driver0, typename Driver1> class GxEPD2_Multi
}
}
// The driver we allocate above is owned by this object, and a single display can only be driven
// by one of them: copying would alias that pointer. There is exactly one instance per device.
GxEPD2_Multi(const GxEPD2_Multi &) = delete;
GxEPD2_Multi &operator=(const GxEPD2_Multi &) = delete;
private:
uint8_t which;
GxEPD2_BW<Driver0, Driver0::HEIGHT> *driver0;