Well the reference won't be invalidated while you are holding it, if that is what you mean. Remember there is still a smart pointer in the vector that manages the resource. You are merely returning a reference to the resource owned by that smart pointer in the vector. Here is some test code that works using smart pointers:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
|
#include <memory>
#include <string_view>
#include <string>
#include <iostream>
#include <vector>
class Environment;
class Document;
class Text
{
friend Document;
std::shared_ptr<Document> _parent;
std::string _text;
void setParent(std::shared_ptr<Document> p) { _parent = p; }
public:
std::string getText() const { return _text; }
void setText(std::string_view text) { _text = text; }
auto& getParent() { return _parent; }
auto const& getParent() const { return _parent; }
};
class Document : public std::enable_shared_from_this<Document>
{
friend Environment;
std::string a;
std::shared_ptr<Environment> _parent;
std::shared_ptr<Text> _text;
void setParent(std::shared_ptr<Environment> p) { _parent = p; }
public:
auto getParent() { return _parent; }
void set_me(std::string b) {a = b;}
auto get_me() {return a;}
auto& getText() { return *_text; }
auto const& getText() const { return *_text; }
void setText(std::shared_ptr<Text> text)
{
_text = text;
_text->setParent(shared_from_this());
}
};
class Environment : public std::enable_shared_from_this<Environment>
{
std::vector<std::shared_ptr<Document>> _docs;
public:
auto& getDocument(int index) { return *_docs[index]; }
auto const& getDocument(int index) const { return *_docs[index]; }
void createDocument()
{
std::shared_ptr<Document> doc = std::make_shared<Document>();
doc->setParent(shared_from_this());
doc->set_me("I am a string that is printed to the screen");
_docs.push_back(std::move(doc));
}
};
int main()
{
auto env = std::make_shared<Environment>();
env->createDocument();
std::cout << env->getDocument(0).get_me() << std::endl;
}
| |
Output:
I am a string that is printed to the screen |
The only time you would have to worry about holding invalid references is when the reference to an object is within a stack frame to a particular function. For example, if you return a reference to a local variable from a function, that reference will now be invalid. Smart pointers manage the lifetime of their resources and are heap allocated, thus the data will remain until the end of the program, where they are destroyed, in which case the smart pointer frees the memory if it knows that there are no other owners (using reference counting).
EDIT:
Unless you mean if the data inside the vector was manually popped_back() by the class at some point while you are still holding a reference. The question then remains why you would want a smart pointer to hold onto the data after the document has been removed from the environment? If the data is removed from the Environment then that means it is no longer required and needs to be freed. You are just extending the lifetime of the document when it is no longer even a part of the Environment anymore. Though, there could be some uses to this, like file recovery and such, I didn't see any of those implemented in your code so I assumed you didn't need those features.
Logically, to me, a document should not be able to exist without an environment because the environment OWNS the document. Even if you were implementing some sort of file recovery methods, this should logically be a part of the Environment class and the client code should not do this by itself. The only interface the client should have is the environment, and the environment should handle its own documents.