Implementing the factory pattern using a pre populated map of objects - c++

I have a map of that maps string ids to a specific implementation of base_object.
Any base_object has a method get_id that returns the id of the object.
and I fill up the map using (pseudo)
void addToMap(base_object* obj){
make_pair(obj->get_id(),obj);
}
This map acts like a factory, and knows to return the correct object using the id. this is the method declaration for retrieving specific object:
base_object* get(string id);
All the objects do not have fields only a polymorphic method that behaves differently for each implementation.
I am not sure what is the best way to implement this.
Should the map be a map of <string,unique_ptr<base_object>>
In this case when I am returning a base_object using get, is it ok to return a raw pointer to base_object? (I know that the map will keep living so that the object will not get destroyed?)
or maybe in this case I should use a shared_ptr?
Also, since the object doesn't really have any fields, maybe it is better to return a copy of the object?
Any way I look at this it looks to me like a bad design, and I just can't decide what is the best approach to solve this.
I am very new to cpp so I am not very familiar with all the differences and best usages of pointers...

Use unique_ptr<base_object> const &. That signals to the caller that what it gets is a handle on a unique object having the id that it requested. Using a shared_ptr signals that it may be responsible for keeping the object alive.
Also, there's no need for a map: you can use a set or unordered_set that orders/hashes based on the id. That way, you won't have to store the id twice.
(The thing you're implementing is more of an object pool than a factory.)

You can use std::unique_ptr<base_object> and return a const reference to the unique_ptr.
Possible implementation:
struct Data
{
std::map<std::string,std::unique_ptr<base_object>> data;
void add(base_object* obj){
data[obj->get_id()] = std::unique_ptr<base_object>(obj);
}
const std::unique_ptr<base_object>& get(const std::string& id) {
return data.at(id);
}
};
Use case example:
Data data;
data.add(new test1_object{});
data["test1"]->create(); // call a virtual function of base_object
Note, that this is not really a factory. If the abstract function of base_object should be responsible for creating your actual product, you can perhaps do this:
struct Factory
{
std::map<std::string,std::unique_ptr<base_object>> workers;
void add(base_object* obj){
data[obj->get_id()] = std::unique_ptr<base_object>(obj);
}
Product create(const std::string& id) {
return data.at(id)->foo(); // call the virtual function here
}
};
Factory factory;
factory.add(new test1_object{});
Product x = factory.create("test1");

The standard of the factory pattern is not filled up with objects on start. There are no objects at all. The factory only knows how to create a new object. A possible implementation can do this with a map and registered static! methods of the class ( not a object ).
And a factory should always return a new instance and not a reference or a pointer to an already existent object. The application typically have no idea how to destroy this special kind of copies instead of own instances.

How you best design your thing depends on the use-cases and design constraints:
If you can guarantee the returned object lives long enough and you can guarantee you'll return an actual object, returning by reference is best (if not having an object to return, there are exceptions. Use where appropriate).
If you can guarantee the returned object lives long enough if there is an object to return, just return by raw pointer.
If all of the maps elements should live to the end of the program, do not make the map own them unless it lives as long and you want to force it to clean them up: Allocate them statically or dynamically (in the second case you might want to register them with std::atexitfor cleanup at the end), and let the map only hold an un-owning raw pointer.
If your program will not be compiled without RTTI and every object is a singleton of its class, consider using typeid for the key (at least the name field) instead of a custom string.
Anyway, you later say the only interesting point of those objects is one single method: Why don't you just use std::function for maximum flexibility?
A std::unordered_map has amortised O(1) access, a std::map only O(ln(n)).

Related

C++: Replace object in std::vector 'in place' with a new object of same type but keep references to this object

is it possible to replace an object in a std::vector with another object of same type and maintain any references to this object which was just replaced?
Let's say we have a
std::vector<MyObj> objs
and I want to replace an MyObj-object such that all references to this MyObj are still intact - is this possible?
You cannot do it in general without some serious misuse of the language (e.g. using placement new in a situation for which it has not been designed). However, you can design MyObj class in a way that makes implementing this use case very straightforward. For example, if MyObj follows the Envelope and Letter Idiom which puts the implementation (the letter) and its wrapper (the envelope) into separate classes, you could make an array of wrappers, and replace their inner content without disturbing outside references:
// The real functionality goes here
struct MyObjImpl {
void operation1() { ... }
void operation2() { ... }
};
// This is a wrapper that forwards calls to the implementation,
// which can be switched at any time without disturbing references to MyObj
class MyObj {
MyObjImpl* wrapped;
public:
MyObj(MyObjImpl* rep) : wrapped(rep) {}
void switch(MyObjectImpl* rep) {
wrapped = rep;
}
void operation1() { wrapped->operation1(); }
void operation2() { wrapped->operation2(); }
};
Assuming that the only way to "replace" an object is to assign to it, then it is in fact unlikely that any references to the assigned-to object are invalidated in the first place.
That is, the answer is: You do not have to do anything special. All references to the "replaced" object remain intact.
Of course, there are other reasons that references to an object held in a std::vector are invalidated, but they do not happen during a well-behaved assignment to the object being held.
Maybe you will want to save states of replaced objects via memento pattern as it's called or just a save state control object. Ref to memento from wiki https://en.wikipedia.org/wiki/Memento_pattern as it's lacking C++ implementation it's simple to write. Also you may want to keep track of replaced objects so might extend it a bit.

Use a unique_ptr and return a reference or should I use a shared_ptr and make copies if needed

I have a cache that stores unique ptrs of objects in an unordered map and returns a reference of the object for users of the cache. It works as it should, storing the objects until they go out of scope.
The cache is implemented as follows:
store objects in cache:
template<typename T>
template<typename... Args>
void ResourceCache<T>::add(const std::string& name, Args... args)
{
m_cache->try_emplace(name, std::make_unique<T>(args...));
}
get object from cache:
template<typename T>
T& ResourceCache<T>::getCachedElement(const std::string& name) const
{
auto it = m_cache->find(name);
if(it != m_cache->end())
return *it->second;
throw "resource not found";
}
But now I walk in to the problem that a reference is not always what I would like to get from the cache, per example:
I have the following object:
class GameObject
{
public:
void translate(const cheetah::Vector3f& position);
protected:
Quaternion m_rotation;
Vector3f m_position;
};
lets say I want the object to have a Texture, currently the only way for me would be to add a member reference
Texture& m_texture
This would result in me having to either
Pass a Texture to the constructor for each object, even if they dont need a texture.
Create a TexturedGameObject that inherits from the GameObject and adds a Texture member and constructor.
Use shared pointers instead of unique pointers and be able to return a copy
Now my question is
What would be seen as best practice in this specific situation? should I use one of the above options or have I missed an even better option?
I know my question is not the most specific but I am learning c++ by myself and it would be nice to get someone elses view on this.
Assuming ResourceCache holds Texture, here's my thoughts. There does not seem to be one best solution in general.
Pass a Texture to the constructor for each object, even if they dont need a texture.
You would need to pass a dummy object so if you want to go with this way, I would suggest keeping it as a raw pointer instead
By doing this you can check if it really has a pointer or not since it can be nullptr
NOTE Either reference or pointer, you should make sure that ResourceCache outlives all GameObject - the lifetimes must be managed manually
Create a TexturedGameObject that inherits from the GameObject and adds a Texture member and constructor.
This could be an option but I think this is more a design issue
Use shared pointers instead of unique pointers and be able to return a copy
This would work fine
Safe (no issues like double-deletion/dangling-pointers)
Shared pointer has overhead

Returning pointer to item cached in a std::map

I have a class which acts as a cache. It has the following private member:
std::map<std::string, Foo> _cache;
I need to write a getter for this cache which returns a reference, pointer, iterator or smart pointer to a Foo object stored in the cache. I want the client to be able to update the Foo object if required via the getter.
However, I don't want the getter to throw if the item is not found in the cache. Instead the client should test the returned value to determine if the item was found. However, I can be convinced to throw if you recommend this approach.
What return type would you recommend for my getter?
I'm using boost and C++98.
Sounds like you need a boost::optional<Foo&> return value (optional references). Your code should look like this:
class YourCache {
std::map<std::string, Foo> _cache;
public:
boost::optional<Foo&> FooByName(const std::string& name)
{
std::map<std::string, Foo>::iterator itr = _cache.find(name);
if(_cache.end() == itr)
return boost::none;
return boost::optional<Foo&>(itr->second);
}
};
getter doesn't throw :)
respects the already existing implementation of _cache (you don't have to change it to store smart pointers - or pointers in general)
gives no direct access to memory in client code (like returning Foo* would)
expresses the intent in the best way ("the return value is optional/could be missing")
offers an explicit and natural interface in client code:
For example:
// client code:
if (boost::optional<Foo&> result = YourCache.FooByName("FOO")) {
// only run if result is in cache
result->bar();
}
In your case references are out of question due to possibility of returning a null pointer. An iterator is a no go either, as you can't test, if it actually points to an element without access to .end() function of the cache, which is a private member. Unless you provide an interface to test is, but that's an overkill.
The only other option is to return a pointer. However that way you'd have to guarantee that the pointer remains valid throughout the whole time a caller uses it. One way to do it is to implement a map of shared pointers, that is:
std::map<std::string, boost::shared_ptr<Foo> > _cache;
That way, even if the object is thrown out of the cache, the caller would still be left with a valid pointer. And shared_ptr can be bool tested, so in case an item is not found in the cache, you could return an empty shared_ptr.
But too little is known about the context of the cache to tell you more (eg if synchronisation is needed, etc).
Use a boost::optional holding a Foo reference as your return value for your getter.

unique_ptr and polymorphism

I have some code that currently uses raw pointers, and I want to change to smart pointers. This helps cleanup the code in various ways. Anyway, I have factory methods that return objects and its the caller's responsibility to manager them. Ownership isn't shared and so I figure unique_ptr would be suitable. The objects I return generally all derive from a single base class, Object.
For example,
class Object { ... };
class Number : public Object { ... };
class String : public Object { ... };
std::unique_ptr<Number> State::NewNumber(double value)
{
return std::unique_ptr<Number>(new Number(this, value));
}
std::unique_ptr<String> State::NewString(const char* value)
{
return std::unique_ptr<String>(new String(this, value));
}
The objects returned quite often need to be passed to another function, which operates on objects of type Object (the base class). Without any smart pointers the code is like this.
void Push(const Object* object) { ... } // push simply pushes the value contained by object onto a stack, which makes a copy of the value
Number* number = NewNumber(5);
Push(number);
When converting this code to use unique_ptrs I've run into issues with polymorphism. Initially I decided to simply change the definition of Push to use unique_ptrs too, but this generates compile errors when trying to use derived types. I could allocate objects as the base type, like
std::unique_ptr<Object> number = NewNumber(5);
and pass those to Push - which of course works. However I often need to call methods on the derived type. In the end I decided to make Push operate on a pointer to the object stored by the unique_ptr.
void Push(const Object* object) { ... }
std::unique_ptr<Object> number = NewNumber(5);
Push(number.get());
Now, to the reason for posting. I'm wanting to know if this is the normal way to solve the problem I had? Is it better to have Push operate on the unique_ptr vs the object itself? If so how does one solve the polymorphism issues? I would assume that simply casting the ptrs wouldn't work. Is it common to need to get the underlying pointer from a smart pointer?
Thanks, sorry if the question isn't clear (just let me know).
edit: I think my Push function was a bit ambiguous. It makes a copy of the underlying value and doesn't actually modify, nor store, the input object.
Initially I decided to simply change the definition of Push to use
unique_ptrs too, but this generates compile errors when trying to use
derived types.
You likely did not correctly deal with uniqueness.
void push(std::unique_ptr<int>);
int main() {
std::unique_ptr<int> i;
push(i); // Illegal: tries to copy i.
}
If this compiled, it would trivially break the invariant of unique_ptr, that only one unique_ptr owns an object, because both i and the local argument in push would own that int, so it is illegal. unique_ptr is move only, it's not copyable. It has nothing to do with derived to base conversion, which unique_ptr handles completely correctly.
If push owns the object, then use std::move to move it there. If it doesn't, then use a raw pointer or reference, because that's what you use for a non-owning alias.
Well, if your functions operate on the (pointed to) object itself and don't need its address, neither take any ownership, and, as I guess, always need a valid object (fail when passed a nullptr), why do they take pointers at all?
Do it properly and make them take references:
void Push(const Object& object) { ... }
Then the calling code looks exactly the same for raw and smart pointers:
auto number = NewNumber(5);
Push(*number);
EDIT: But of course no matter if using references or pointers, don't make Push take a std::unique_ptr if it doesn't take ownership of the passed object (which would make it steal the ownership from the passed pointer). Or in general don't use owning pointers when the pointed to object is not to be owned, std::shared_ptr isn't anything different in this regard and is as worse a choice as a std::unique_ptr for Push's parameter if there is no ownership to be taken by Push.
If Push does not take owenrship, it should probably take reference instead of pointer. And most probably a const one. So you'll have
Push(*number);
Now that's obviously only valid if Push isn't going to keep the pointer anywhere past it's return. If it does I suspect you should try to rethink the ownership first.
Here's a polymorphism example using unique pointer:
vector<unique_ptr<ICreature>> creatures;
creatures.emplace_back(new Human);
creatures.emplace_back(new Fish);
unique_ptr<vector<string>> pLog(new vector<string>());
for each (auto& creature in creatures)
{
auto state = creature->Move(*pLog);
}

Accessing Members of Containing Objects from Contained Objects

If I have several levels of object containment (one object defines and instantiates another object which define and instantiate another object..), is it possible to get access to upper, containing - object variables and functions, please?
Example:
class CObjectOne
{
public:
CObjectOne::CObjectOne() { Create(); };
void Create();
std::vector<ObjectTwo>vObejctsTwo;
int nVariableOne;
}
bool CObjectOne::Create()
{
CObjectTwo ObjectTwo(this);
vObjectsTwo.push_back(ObjectTwo);
}
class CObjectTwo
{
public:
CObjectTwo::CObjectTwo(CObjectOne* pObject)
{
pObjectOne = pObject;
Create();
};
void Create();
CObjectOne* GetObjectOne(){return pObjectOne;};
std::vector<CObjectTrhee>vObjectsTrhee;
CObjectOne* pObjectOne;
int nVariableTwo;
}
bool CObjectTwo::Create()
{
CObjectThree ObjectThree(this);
vObjectsThree.push_back(ObjectThree);
}
class CObjectThree
{
public:
CObjectThree::CObjectThree(CObjectTwo* pObject)
{
pObjectTwo = pObject;
Create();
};
void Create();
CObjectTwo* GetObjectTwo(){return pObjectTwo;};
std::vector<CObjectsFour>vObjectsFour;
CObjectTwo* pObjectTwo;
int nVariableThree;
}
bool CObjectThree::Create()
{
CObjectFour ObjectFour(this);
vObjectsFour.push_back(ObjectFour);
}
main()
{
CObjectOne myObject1;
}
Say, that from within CObjectThree I need to access nVariableOne in CObjectOne. I would like to do it as follows:
int nValue = vObjectThree[index].GetObjectTwo()->GetObjectOne()->nVariable1;
However, after compiling and running my application, I get Memory Access Violation error.
What is wrong with the code above(it is example, and might contain spelling mistakes)?
Do I have to create the objects dynamically instead of statically?
Is there any other way how to achieve variables stored in containing objects from withing contained objects?
When you pass a pointer that points back to the container object, this pointer is sometimes called a back pointer. I see this technique being used all the time in GUI libraries where a widget might want access to its parent widget.
That being said, you should ask yourself if there's a better design that doesn't involve circular dependencies (circular in the sense that the container depends on the containee and the containee depends on the container).
You don't strictly have to create the objects dynamically for the back pointer technique to work. You can always take the address of a stack-allocated (or statically-allocated) object. As long as the life of that object persists while others are using pointers to it. But in practice, this technique is usually used with dynamically-created objects.
Note that you might also be able to use a back-reference instead of a back-pointer.
I think I know what's causing your segmentation faults. When your vectors reallocate their memory (as the result of growing to a larger size), the addresses of the old vector elements become invalid. But the children (and grand-children) of these objects still hold the old addresses in their back-pointers!
For the back-pointer thing to work, you'll have to allocate each object dynamically and store their pointers in the vectors. This will make memory management a lot more messy, so you might want to use smart pointers or boost::ptr_containers.
After seeing the comment you made in another answer, I now have a better idea of what you're trying to accomplish. You should research generic tree structures and the composite pattern. The composite pattern is usually what's used in the widget example I cited previously.
Maybe all your object can inherit from a common interface like :
class MyObject
{
public:
virtual int getData() = 0;
}
And after you can use a std::tree from the stl library to build your structure.
As Emile said, segmentation fault is caused by reallocation. Exactly speaking -- when the local stack objects' 'this' pointer was passed to create another object, which is then copied to the vector container. Then the 'Create()' function exits, the stack frame object ceases to exist and the pointer in the container gets invalid.