1

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?

7
  • Use some other container instead of std::vector? Commented May 16, 2021 at 22:32
  • 1
    ^^ such as std::list<T> for example Commented May 16, 2021 at 22:33
  • There is any alternative in the standard library? Commented May 16, 2021 at 22:33
  • I just mentioned one Commented May 16, 2021 at 22:33
  • 1
    You can have vector of share_ptr & return weak_ptr, this way you can make sure correct referecing. Commented May 16, 2021 at 23:34

2 Answers 2

2

What could be a good and safe way of doing this?

Saving the couple (vector reference, Foo's index), assuming Foos 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};
  }
};

Live example

Sign up to request clarification or add additional context in comments.

Comments

1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.