From our conversation in the comments it seems to me that separating concerns might be in order.
An A is an attribute of a B. There needs to be a canonical store of Bs (that controls lifetime) and there needs to be an index (non-owning) of Bs ordered by some attribute of the B (in this case, one of the As).
This argues for two vectors (or some other appropriate container), one containing Bs and the other containing sorted references to Bs.
You can of course wrap the container and index into another object to provide encapsulation (I have not done this in the trivial example below):
#include <vector>
#include <algorithm>
#include <memory>
#include <functional>
// define the attribute
struct A
{
float f;
A(float f)
: f(f)
{}
};
// define the object
struct B
{
A a1;
A a2;
// no back-pointers
B(float f, float f2)
: a1(f)
, a2(f2)
{}
};
int main()
{
using b_vec_type = std::vector<B>;
// build the canonical store
b_vec_type bs = { B { 1, 2}, B { 5, 4 }, B { 3, 4 } };
using a1_index_type = std::vector<std::reference_wrapper<B>>;
// build the index
a1_index_type index(bs.begin(), bs.end());
// sort the index by the attribute we want
std::sort(index.begin(), index.end(),
[](const B& l, const B& r) {
return l.a1.f < r.a1.f;
});
// now use the index:
for (const auto& e : index)
{
// do something with the Bs, ordered by B::a1
// e will be of type std::reference_wrapper<B>, which has
// a conversion operator to B& already defined.
}
return 0;
}