Commit 25d8f193 for tesseract

commit 25d8f193f48af9017398c80fe8d3240b4d8ad457
Author: Stefan Weil <sw@weilnetz.de>
Date:   Sun Aug 9 14:58:53 2026 +0200

    Fix CID 1451544 (Resource leak in object)

    MERGE_CLASS_NODE allocated its Class member in the constructor but
    had no destructor to free it, so every deletion of the node had to
    free the class manually. Add a destructor which frees the class and
    drop the now redundant explicit FreeClass call.

    Assisted-by: OpenCode / big-pickle (opencode)
    Signed-off-by: Stefan Weil <sw@weilnetz.de>

diff --git a/src/training/common/commontraining.cpp b/src/training/common/commontraining.cpp
index 6af647c0..c02b805b 100644
--- a/src/training/common/commontraining.cpp
+++ b/src/training/common/commontraining.cpp
@@ -618,7 +618,6 @@ void FreeLabeledClassList(LIST ClassList) {
   iterate(ClassList) /* iterate through all of the fonts */
   {
     MergeClass = reinterpret_cast<MERGE_CLASS>(ClassList->first_node());
-    FreeClass(MergeClass->Class);
     delete MergeClass;
   }
   destroy(nodes);
diff --git a/src/training/common/commontraining.h b/src/training/common/commontraining.h
index e94fc64b..7ffebe04 100644
--- a/src/training/common/commontraining.h
+++ b/src/training/common/commontraining.h
@@ -91,6 +91,12 @@ using LABELEDLIST = LABELEDLISTNODE *;
 struct MERGE_CLASS_NODE {
   MERGE_CLASS_NODE(const char * label) : Label(label), Class(NewClass(MAX_NUM_PROTOS, MAX_NUM_CONFIGS)) {
   }
+  ~MERGE_CLASS_NODE() {
+    FreeClass(Class);
+  }
+  // Class owns a raw pointer, so copying the node would double free it.
+  MERGE_CLASS_NODE(const MERGE_CLASS_NODE &) = delete;
+  MERGE_CLASS_NODE &operator=(const MERGE_CLASS_NODE &) = delete;
   std::string Label;
   int NumMerged[MAX_NUM_PROTOS];
   tesseract::CLASS_TYPE Class;