c++ - shared_ptr, unique_ptr, ownership, Am I overdoing it in this particular case? -


i work on graphics applications , have been using shared & unique pointers because handles memory deallocation me (aka convenience) bad (if that's reason why use them).

i read answer question on stackoverflow mentioned according b. stroustrup, unique/shared ptrs should not used , arguments should passed value instead.

i have case in graphics think using shared_ptr makes sense i'd know experts (i not c++ experts) if on doing/thinking , if doing instead (to conform c++ recommendations , efficiency)

i take general problem occurs in rendering/ray-tracing. in particular problem have pool of objects (we use triangles explanation) , structure simplicity of explanation refer regular 3d grid. let's @ point need insert triangles grid: means need check of bounding volume of each inserted triangle overlaps of cells grid, , does, each overlapped cell needs keep pointer/reference triangle (for later use). triangle may overlap more 1 cell, can referenced multiples times several cells (you see going shared_ptr here).

note outside of grid structure, don't need pool of triangles (so technically object owns pool of triangle here, grid or more precisely grid's cells).

class grid {     struct cell     {         std::vector<std::shared_ptr<const triangle>> trilist;      };     void insert(triangle*& tri_)     {         std::shared_ptr<const triangle> tri = tri_;         (each cell overlapped tri) {             // compute cell index             uint32_t = ...             cells[i].trilist.push_back(tri);         }     }     cell cells[res * res * res]; };  void createpooloftrianglesandinsertintogrid() {     grid grid;     uint32_t maxtris = 32;     triangle* tris = new triangles[maxtris];     // process triangles     ...     // insert grid     (uint32_t = 0; < maxtris; ++i) {         // use placement new         triangle* tri = new (&tris[i]) triangle;         grid.insert(tri);     }     // no need delete tris here ... should done      // grid when go out of function's scope } 

it sounds complicated motivation behind design follow stroustrup's recommendation. in case function createpooloftrianglesandinsertintogrid doesn't owned triangles, it's cells of grid do. allocate memory in function createpooloftrianglesandinsertintogrid because need create triangles, , use placement new method pointer each triangle in pool can pass grid insert method (i defer memory management of object method). in there, converts triangle shared_ptr , cells can share "reference" (using shared_ptr).

i wanted know if opinion going in right direction, or if appears wrong, both in terms of implementation , in terms of possible loss of efficiency (i allocate pool of memory, use new placement create temp triangle, pass on grid insert method, convert shared_ptr, ...)

i trying both learn, , improve code , hope can provide valuable professional feedback.

edit: trying find right approach problem + try provide later modifications based on comments

it looks me grid owns triangles. assuming triangles relatively light (3-5 dimensions?).

i think might suit. using container in grid take ownership of triangles by value. container delete triangles when grid goes out of scope.

then each cell uses raw pointers keep track of triangles references. cells don't own triangles hold pointers triangles owned grid.

class grid {     struct cell     {         std::vector<triangle*> trilist; // non owning     };      void insert(triangle tri) // pass value     {         tris.push_back(tri); // grid owns value          for(each cell overlapped tri) {             // compute cell index             uint32_t = ...              cells[i].trilist.push_back(&tris.back());         }     }      // use deque because won't re-allocate when adding     // new elements end     std::deque<triangle> tris; // elements owned value     cell cells[res * res * res]; // point owned elements };  void createpooloftrianglesandinsertintogrid() {     grid grid; // owns triangles (by value)      uint32_t maxtris = 32;      std::vector<triangle> tris(maxtris);     // process triangles     // ...     // insert grid     for(auto tri: tris)         grid.insert(tri);     }      // no need delete tris here ... should done     // grid when go out of function's scope } 

note: use std::deque store triangles value in grid. that's because won't ever reallocate internal memory when adding new triangles. if used std::vector here raw pointers end dangling when std::vector resized itself.

alternatively:

given looks build triangles in function , pass of them grid, why 1 @ time? pass whole container in in 1 go. if using move semantics won't have copy anything:

class grid {     struct cell     {         std::vector<triangle*> trilist; // non owning     };      // accept entire container in-tack     // (no reallocations allowed after point)     void insert(std::vector<triangle> tris) // pass value (able move in)     {         //         for(auto& tri: tris)         {             for(each cell overlapped tri) {                 // compute cell index                 uint32_t = ...                  cells[i].trilist.push_back(&tri);             }         }     }      // using vector must not resized after     // cells have been pointed elements!!!     std::vector<triangle> tris; // elements owned value     cell cells[res * res * res]; // point owned elements };  void createpooloftrianglesandinsertintogrid() {     grid grid; // owns triangles (by value)      uint32_t maxtris = 32;      // build triangles     std::vector<triangle> tris(maxtris);     // process triangles     // ...     // insert grid     grid.insert(std::move(tris)); // move whole darn container (very efficient)      // no need delete tris here ... should done     // grid when go out of function's scope } 

note: used std::vector because not adding triangles 1 one after arrive in grid. must make sure inside grid owning `std::vector not resized.


Comments