Reputation: 1272
I will like to create a struct that holds a higher state for other structs.
I tried to create it like this, but I recently found that returning a pointer to an element of an std::vector is not safe, since that pointer can change.
struct Foo {
std::string &context;
std::string content;
Foo(std::string &context, std::string content) : context(context), content(content) {}
}
struct Bar {
std::string context;
std::vector<std::string> manyFoos;
Foo* addFoo(std::string content) {
manyFoos.emplace_back(context, content);
return &manyFoos[manyFoos.size() - 1];
}
}
struct Example {
Bar bar;
Foo* fooA;
Foo* fooB;
Example() {
fooA = bar.addFoo("Hello");
fooB = bar.addFoo("World");
}
}
What could be a good and safe way of doing this?
Upvotes: 1
Views: 693
Reputation: 1585
You can have vector of shared_ptr & return weak_ptr, this way you can make sure correct referencing
#include <iostream>
#include <vector>
#include <memory>
struct Foo {
std::string &context;
std::string content;
Foo(std::string &context, std::string content) : context(context), content(content) {}
};
struct Bar {
std::string context;
std::vector<std::shared_ptr<Foo>> manyFoos;
std::weak_ptr<Foo> addFoo(std::string content) {
auto foo = std::make_shared<Foo>(context, content);
manyFoos.emplace_back(foo);
return foo;
}
};
void printFoo(std::weak_ptr<Foo> foo)
{
// Here we are checking weak_ptr expiry
std::cout << (foo.expired() ? "Foo Expired" : foo.lock()->content) << std::endl;
}
int main() {
Bar bar;
std::weak_ptr<Foo> fooA;
std::weak_ptr<Foo> fooB;
fooA = bar.addFoo("Hello");
fooB = bar.addFoo("World");
printFoo(fooA);
printFoo(fooB);
// erase last element
bar.manyFoos.pop_back();
printFoo(fooB);
return 0;
}
Output:
Hello
World
Foo Expired
Upvotes: 1
Reputation: 40100
What could be a good and safe way of doing this?
Saving the couple (vector reference, Foo
's index), assuming Foo
s are only added at the back.
With a bit of syntaxic sugar:
struct Bar {
std::string context;
std::vector<Foo> manyFoos;
struct FooProxy
{
std::vector<Foo>& foos;
std::vector<Foo>::size_type index;
operator Foo() { return foos[index]; }
};
auto addFoo(std::string content) {
manyFoos.emplace_back(context, content);
return FooProxy{manyFoos, manyFoos.size()-1};
}
};
Upvotes: 2