Here you specified that the precondition is that Element
and Face
objects are created in a Grid
object with the elements of the container referring to the same Grid
containers, therefore the lifetime of all three containers (points
, elms
and faces
) is the same.
Now you have to consider two cases.
Semi-immutable points
In this case, points
is guaranteed to never invalidate references to its elements (eg. it's never modified). Here you don't need any smart pointers, you can just use a simple std::reference_wrapper
as follows:
struct Vector3
{
std::vector<double> dim;
Vector3 () : dim(3) {}
};
template<class Type>
using ref_vec = std::vector<std::reference_wrapper<Type>>;
struct Element { ref_vec<Vector3> points; };
struct Face { ref_vec<Vector3> points; };
struct Grid
{
std::vector<Vector3> points;
std::vector<Element> elms;
std::vector<Face> faces;
};
Another solution, non equivalent to your example (elms
and faces
don't have direct access to the Vector3
object) might be to use indexes:
struct Vector3
{
std::vector<double> dim;
Vector3 () : dim(3) {}
};
struct Grid
{
struct Element { std::size_t point_indices; };
struct Face { std::size_t point_indices; };
std::vector<Vector3> points;
std::vector<Element> elms;
std::vector<Face> faces;
};
That is, you store the indices of points
.
Mutable points
If the operations performed on points
can invalidate references, then you might want to consider another container that does not invalidate references/pointers/iterators to the element.
For example std::deque
guarantees the validity of references for deletion/insertion at the beginning and end of the container.
Once you have chosen the correct container you can just apply the same ideas as above.