Skip to content

Commit fc25980

Browse files
zhaozhiwenclaude
andcommitted
Free G4World's G4Volume wrappers; forbid copy/move to avoid double-free
G4World stored raw G4Volume* wrappers in g4volumesMap but had no destructor, so every g4world.reset() on geometry reload leaked one wrapper per volume — unbounded growth in long interactive sessions. Add a destructor that deletes the wrappers (Geant4 owns the contained solid/logical/physical objects, so only the lightweight GEMC wrappers are freed). Because G4World previously inherited GBase's defaulted copy/move, adding an owning destructor would make a shallow copy double-free; G4World is only ever held by shared_ptr, so delete copy and move to forbid relocation. Verified the deletions don't break the build (nothing copies or moves G4World). Fixes #135 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 48f83e5 commit fc25980

1 file changed

Lines changed: 13 additions & 0 deletions

File tree

gemc/g4system/g4world.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,19 @@ class G4World : public GBase<G4World>
6363
*/
6464
G4World(const GWorld* gworld, const std::shared_ptr<GOptions>& gopts);
6565

66+
/// Frees the owned G4Volume wrappers. Geant4 owns the contained solid/logical/physical
67+
/// objects, so only the lightweight wrappers allocated by the object factories are deleted.
68+
~G4World() {
69+
for (auto& [name, vol] : g4volumesMap) { delete vol; }
70+
}
71+
72+
// G4World now owns the raw G4Volume* wrappers (freed in the destructor). It is only ever held
73+
// by shared_ptr, so forbid copy/move to avoid a shallow copy double-freeing the wrappers.
74+
G4World(const G4World&) = delete;
75+
G4World& operator=(const G4World&) = delete;
76+
G4World(G4World&&) = delete;
77+
G4World& operator=(G4World&&) = delete;
78+
6679
// ────── lookup / mutators ────────────────────────────────────────
6780

6881
/**

0 commit comments

Comments
 (0)