1313#include " ../struct/particle.h"
1414#include < vector>
1515#include < cmath>
16+ #include < memory> // Required for unique_ptr
1617#include " dt/softening.h"
1718#include " floatdef.h"
1819
@@ -22,35 +23,50 @@ struct Octree {
2223 real x, y, z; // node center
2324 real size; // half-width
2425 bool leaf = true ;
25- Particle* body = nullptr ;
26- Octree* child[8 ] = { nullptr };
26+ Particle* body = nullptr ;
27+
28+ // Ownership: unique_ptr handles memory automatically
29+ std::unique_ptr<Octree> child[8 ] = { nullptr , nullptr , nullptr , nullptr , nullptr , nullptr , nullptr , nullptr };
2730
2831 // Quadrupole tensor
2932 real Qxx = 0 , Qyy = 0 , Qzz = 0 ;
3033 real Qxy = 0 , Qxz = 0 , Qyz = 0 ;
3134
3235 Octree (real X, real Y, real Z, real S) : x(X), y(Y), z(Z), size(S), m(0 ), cx(0 ), cy(0 ), cz(0 ) {}
3336
34- ~Octree () { for (auto c : child) delete c; }
37+ // Destructor is now empty; unique_ptr cleans up children automatically
38+ ~Octree () = default ;
3539
3640 int index (const Particle& p) const {
3741 return (p.x > x) * 1 + (p.y > y) * 2 + (p.z > z) * 4 ;
3842 }
3943
40- Octree* createChild (int idx) {
44+ // Returns unique_ptr to take ownership
45+ std::unique_ptr<Octree> createChild (int idx) {
4146 real hs = size * real (0.5 );
42- return new Octree (x + ((idx & 1 ) ? hs : -hs), y + ((idx & 2 ) ? hs : -hs), z + ((idx & 4 ) ? hs : -hs), hs);
47+ return std::make_unique<Octree>(
48+ x + ((idx & 1 ) ? hs : -hs),
49+ y + ((idx & 2 ) ? hs : -hs),
50+ z + ((idx & 4 ) ? hs : -hs),
51+ hs
52+ );
4353 }
4454
4555 void insert (Particle* p) {
46- if (leaf && body == nullptr ) { body = p; return ; }
56+ if (leaf && body == nullptr ) {
57+ body = p;
58+ return ;
59+ }
60+
4761 if (leaf) {
4862 leaf = false ;
49- Particle* old = body; body = nullptr ;
63+ Particle* old = body;
64+ body = nullptr ;
5065 int idx = index (*old);
5166 if (!child[idx]) child[idx] = createChild (idx);
5267 child[idx]->insert (old);
5368 }
69+
5470 int idx = index (*p);
5571 if (!child[idx]) child[idx] = createChild (idx);
5672 child[idx]->insert (p);
@@ -65,7 +81,7 @@ struct Octree {
6581 }
6682
6783 m = 0 ; cx = cy = cz = 0 ;
68- for (auto c : child) {
84+ for (auto & c : child) { // Use reference to unique_ptr
6985 if (!c) continue ;
7086 c->computeMass ();
7187 if (c->m == 0 ) continue ;
@@ -75,10 +91,9 @@ struct Octree {
7591 if (m > 0 ) { cx /= m; cy /= m; cz /= m; }
7692
7793 Qxx = Qyy = Qzz = Qxy = Qxz = Qyz = 0 ;
78- for (auto c : child) {
94+ for (auto & c : child) {
7995 if (!c || c->m == 0 ) continue ;
8096 real rx = c->cx - cx; real ry = c->cy - cy; real rz = c->cz - cz;
81- // Internal node softening to match force calculation
8297 real r2 = rx * rx + ry * ry + rz * rz + (size * size * real (0.01 ));
8398 real mchild = c->m ;
8499 Qxx += mchild * (3 * rx * rx - r2);
@@ -91,6 +106,7 @@ struct Octree {
91106 }
92107};
93108
109+ // Traverse using raw pointers (non-owning observer)
94110inline void bhAccel (Octree* node, const Particle& p, real theta, real& ax, real& ay, real& az) {
95111 if (!node || node->m == 0 ) return ;
96112 if (node->leaf && node->body == &p) return ;
@@ -131,5 +147,7 @@ inline void bhAccel(Octree* node, const Particle& p, real theta, real& ax, real&
131147 return ;
132148 }
133149
134- for (auto c : node->child ) if (c) bhAccel (c, p, theta, ax, ay, az);
150+ for (auto & c : node->child ) {
151+ if (c) bhAccel (c.get (), p, theta, ax, ay, az); // Use .get() to pass raw pointer
152+ }
135153}
0 commit comments