I am implementing a task runtime system that maintains buffers for user-provided objects of various types. In addition, all objects are wrapped before they are stored into the buffers. Since the runtime doesn't know the types of objects that the user will provide, the Wrapper and the Buffer classes are templated:
template <typename T>
class Wrapper {
private:
T mdata;
public:
Wrapper() = default;
Wrapper(T& user_data) : mdata(user_data) {}
T& GetData() { return mdata; }
...
};
template <typename T>
class Buffer {
private:
std::deque<Wrapper<T>> items;
public:
void Write(Wrapper<T> wd) {
items.push_back(wd);
}
Wrapper<T> Read() {
Wrapper<T> tmp = items.front();
items.pop_front();
return tmp;
}
...
};
Now, the runtime system handles the tasks, each of which operates on a subset of aforementioned buffers. Thus, each buffer is operated by one or more tasks. This means that a task must keep references to the buffers since the tasks may share buffers.
This is where my problem is:
1) each task needs to keep references to a number of buffers (this number is unknown in compile time)
2) the buffers are of different types (based on the templeted Buffer class).
3) the task needs to use these references to access buffers.
There is no point to have a base class to the Buffer class and then use base class pointers since the methods Write and Read from the Buffer class are templeted and thus cannot be virtual.
So I was thinking to keep references as void pointers, where the Task class would look something like:
class Task {
private:
vector<void *> buffers;
public:
template<typename T>
void AddBuffer(Buffet<T>* bptr) {
buffers.push_back((void *) bptr);
}
template<typename T>
Buffer<T>* GetBufferPtr(int index) {
return some_way_of_cast(buffers[index]);
}
...
};
The problem with this is that I don't know how to get the valid pointer from the void pointer in order to access the Buffer. Namely, I don't know how to retain the type of the object pointed by buffers[index].
Can you help me with this, or suggest some other solution?
EDIT: The buffers are only the implementation detail of the runtime system and the user is not aware of their existence.
In my experience, when the user types are kept in user code, run-time systems handling buffers do not need to worry about the actual type of these buffer. Users can invoke operations on typed buffers.
class Task {
private:
vector<void *> buffers;
public:
void AddBuffer(char* bptr) {
buffers.push_back((void *) bptr);
}
char *GetBufferPtr(int index) {
return some_way_of_cast(buffers[index]);
}
...
};
class RTTask: public Task {
/* ... */
void do_stuff() {
Buffer<UserType1> b1; b1Id = b1.id();
Buffer<UserType2> b2; b2Id = b2.id();
AddBuffer(cast(&b1));
AddBuffer(cast(&b2));
}
void do_stuff2() {
Buffer<UserType1> *b1 = cast(GetBufferPtr(b1Id));
b1->push(new UserType1());
}
};
In these cases casts are in the user code. But perhaps you have a different problem. Also the Wrapper class may not be necessary if you can switch to pointers.
What you need is something called type erasure. It's way to hide the type(s) in a template.
The basic technique is the following:
- Have an abstract class with the behavior you want in declared in a type independent maner.
- Derive your template class from that class, implement its virtual methods.
Good news, you probably don't need to write your own, there boost::any already. Since all you need is get a pointer and get the object back, that should be enough.
Now, working with void* is a bad idea. As perreal mentioned, the code dealing with the buffers should not care about the type though. The good thing to do is to work with char*. That is the type that is commonly used for buffers (e.g. socket apis). It is safer than too: there is a special rule in the standard that allows safer conversion to char* (see aliasing rules).
This isn't exactly an answer to your question, but I just wanted to point out that the way you wrote
Wrapper<T> Read() {
makes it a mutator member function which returns by value, and as such, is not good practice as it forces the user write exception unsafe code.
For the same reason the STL stack::pop() member function returns void, not the object that was popped off the stack.
Related
I want to implement a resource loader, and conceptually, it feels like all the resources in SDL2 are the same; you need to free the resource when finished, SDL_Texture* with SDL_DestroyTexture, Mix_Music* with Mix_FreeMusic, Mix_Chunk* with Mix_FreeChunk, TTF_Font* with TTF_CloseFont. All that changes is the name of the "deleter" function, so I would like to box these all so I don't need 4 different std::maps for each type of resource.
I've implemented a small class that boxes the data, but I'm having trouble getting the types back when using generics. Specifically, I get "SDL_Texture* is an incomplete type" when I try to cast the void* back to SDL_Texture* via value.get<SDL_Texture*>()
ValueBox.h
// helper class used to box various pointers for sdl, like textures, chunks, fonts, etc
class ValueBox {
public:
std::function<void(void)> clean;
void* data;
ValueBox(void* data, std::function<void(void)> clean) : data(data), clean( std::move(clean) ) {}
~ValueBox() {
clean();
}
template<typename T>
T get() {
return dynamic_cast<T>(data);
}
};
How do I implement a class that allows me to box the pointers so that I don't need four different maps in the loader? (Or am I doing something that I shouldn't?)
dynamic_cast only makes sense when you're casting to a polymorphic type (or void*), from a polymorphic type. A polymorphic type is a class (or a struct, which is formally also a class) that has (possibly inherits) at least one virtual function.
None of the types you listed are polymorphic (because they come from C libraries, and C doesn't have virtual functions). But even if they were, void itself is not polymorphic, so it wouldn't work anyway.
Additionally, you must dynamic_cast to a pointer or reference, but it doesn't matter because of the above.
Since all your resources are pointers, you can [ab]use std::unique_ptr to dispose of them automatically. Here's an example for FILE * and std::fopen:
using file_ptr = std::unique_ptr<FILE, std::integral_constant<decltype(&std::fclose), std::fclose>>;
int main()
{
file_ptr f(std::fopen("foo.txt", "rb")); // This is closed automatically.
}
However, I don't recommend doing so, because it only works with pointers. If you encounter a new type of resource that's not a pointer, you'll have to manage it differently, making your code inconsistent.
You could in theory write a class similar to std::unique_ptr that's not limited to pointers, but after trying this myself, I decided that it's not very convenient and not worth the effort.
I suggest writing an individual class for each kind of resource, using following pattern:
class FilePtr
{
FILE* file = nullptr;
public:
FilePtr() {} // Optional
FilePtr(const char *filename, const char *mode) // Change parameters as needed.
{
file = std::fopen(filename, mode);
if (!file)
throw std::runtime_error("Can't open file!");
}
FilePtr(FilePtr &&other) noexcept : file(std::exchange(other.file, {})) {}
FilePtr &operator=(FilePtr other) noexcept
{
std::swap(file, other.file);
return *this;
}
~FilePtr()
{
if (file)
std::fclose(file);
)
[[nodiscard]] explicit operator bool() const {return bool(file);} // Optional.
// Add more functions as needed.
};
Since those wrappers are so simple, you can easily write them for each kind of resource.
Having individual classes also allows you to add resource-specific functions to them.
class that allows me to box the pointers so that I don't need four different maps in the loader?
I would use different maps. This means you don't need to validate resource type at runtime, meaning one less failure point.
But regardless of the number of maps, you can inherit your wrapper classes from a single base, to reduce code duplication.
If you make the base polymorphic, you'll be able to store the resources in a single map of shared_ptrs (or unique_ptrs) to that base.
I have a custom container class that is templated:
template<typename T>
class MyContainer {
T Get();
void Put(T data);
};
I would like to pass a pointer to this container to a function that will access the container's data as generic data - i.e. char* or void*. Think serialization. This function is somewhat complicated so it would be nice to not specify it in the header due to the templates.
// Errors of course, no template argument
void DoSomething(MyContainer *container);
I'm ok with requiring users to provide a lambda or subclass or something that performs the conversion. But I can't seem to come up with a clean way of doing this.
I considered avoiding templates altogether by making MyContainer hold a container of some abstract MyData class that has a virtual void Serialize(void *dest) = 0; function. Users would subclass MyData to provide their types and serialization but that seems like it's getting pretty complicated. Also inefficient since it requires storing pointers to MyData to avoid object slicing and MyData is typically pretty small and the container will hold large amounts (a lot of pointer storage and dereferencing).
You don't need any char* or void* or inheritance.
Consider this simplified implementation:
template <class T>
void Serialize (std::ostream& os, const MyContainer<T>& ct) {
os << ct.Get();
}
Suddenly this works for any T that has a suitable operator<< overload.
What about user types that don't have a suitable operator<< overload? Just tell the users to provide one.
Of course you can use any overloaded function. It doesn't have to be named operator<<. You just need to communicate its name and signature to the users and ask them to overload it.
You can introduce a non-template base class for the container with a pure virtual function that returns a pointer to raw data and implement it in your container:
class IDataHolder
{
public:
virtual ~IDataHolder(); // or you can make destructor protected to forbid deleteing by pointer to base class
virtual const unsigned char* GetData() const = 0;
};
template<typename T>
class MyContainer : public IDataHolder
{
public:
T Get();
void Put(T data);
const unsigned char* GetData() const override { /* cast here internal data to pointer to byte */}
};
void Serialize(IDataHolder& container)
{
const auto* data = container.GetData();
// do the serialization
}
I would like to pass a pointer to this container to a function that will access the container's data as generic data - i.e. char* or void*. Think serialization.
Can't be done in general, because you don't know anything about T. In general, types cannot be handled (e.g. copied, accessed, etc.) as raw blobs through a char * or similar.
Therefore, you would need to restrict what T can be, ideally enforcing it, otherwise never using it for Ts that would trigger undefined behavior. For instance, you may want to assert that std::is_trivially_copyable_v<T> holds. Still, you will have to consider other possible issues when handling data like that, like endianness and packing.
This function is somewhat complicated so it would be nice to not specify it in the header due to the templates.
Not sure what you mean by this. Compilers can handle very easily headers, and in particular huge amounts of template code. As long as you don't reach the levels of e.g. some Boost libraries, your compile times won't explode.
I considered avoiding templates altogether by making MyContainer hold a container of some abstract MyData class that has a virtual void Serialize(void *dest) = 0; function. Users would subclass MyData to provide their types and serialization but that seems like it's getting pretty complicated. Also inefficient since it requires storing pointers to MyData to avoid object slicing and MyData is typically pretty small and the container will hold large amounts (a lot of pointer storage and dereferencing).
In general, if you want a template, do a template. Using dynamic dispatching for this will probably kill performance, specially if you have to go through dispatches for even simple types.
As a final point, I would suggest taking a look at some available serialization libraries to see how they achieved it, not just in terms of performance, but also in terms of easy of use, integration with existing code, etc. For instance, Boost Serialization and Google Protocol Buffers.
There is a templated class, let it be
template<typename T> class A { std::vector<T> data; };
The problem I am facing here is, users can create several types of this class, but I need to track them, best case is I have a reference of these objects in another vector, but that would not work since all types are different.
Can you recommend a good design pattern which can encapsulate this.
I can store pointers and then typecast it, but its not elegant.
I can change the architecture as well, if the solution provided is good enough.
The basic question I am trying to solve is, I have a class of vector of custom types, how do I store them.
As previous comments stated - you first need to make sure this is what you need.
With that been said, I had a similar requirement in a project of mine, which I eventually solved with inheritance and PIMPL, as follows:
class A{
private:
struct Abstract {
virtual void f() = 0;
};
template <typename T>
struct Implementation : public Abstract {
std::vector<T> data;
virtual void f() {...}
};
std::unique_ptr<Abstract> impl;
public:
template <typename T>
A(): impl(std::make_unique<Implementation<T> >()){}
void f() {impl->f();}
};
This allows you to create a container of objects of type A, and access them via the public interface defined therein (the method f). The underlying type T of each A object is specified on construction. All other implementation details specific to the type T are hidden.
The solution suffers the inherent overhead of virtual functions. I'm not sure how it compares to the std::any approach performance-wise.
std::any is the modern c++17 solution. Specifically, you should use
A<int> a;
a.data.push_back(0);
// fill refernces...
std::vector<std::any> refernces;
refernces.push_back(&a.data[0]);
// check which type is active.
if(int** iPtr = std::any_cast<int*>(&references[0]); iPtr != nullptr)
{
// its an int*
int& i = **iPtr;
// do something with i.
}
These pointers can point into the A<int>::data and A<double>::data vectors.
For a complete reference, see here https://en.cppreference.com/w/cpp/utility/any.
I am making the engine for a game and I can't seem to solve the following problem.
So, I have a base component class from which all the different components are derived. A GameObject is basically a container for different components. The components are stored in a vector containing pointers to the base component class. Now I need the GameObject class to have a getComponent member function template that will return the component with the requested type from the vector.
To be more clear:
class Component
{
/..../
};
class RigidBody : Component
{
/..../
};
class Animation : Component
{
/..../
};
class GameObject
{
public:
template <class T>
T* getComponent();
void addComponent(Component*);
private:
std::vector<Component*> m_components;
};
/...../
GameObject test;
test.AddComponent(new RigidBody());
test.AddComponent(new Animation());
Animation * animation = test.getComponent<Animation>();
Or something among those lines.
For simplicity's sake say that the vector is guaranteed to have the component that we are looking for and that there are no components of the same type.
Since the pointers in the vector are of the base component type, how can I check if they originally were of the requested type? Thanks in advance!
Assuming that Component has at least one virtual function (otherwise what's the point of inheriting from it, right?) you should be able to do what you need using Runtime Type Information (RTTI) and dynamic_cast, like this:
template <class T> T* getFirstComponent() {
for (int i = 0 ; i != m_components.size() ; i++) {
T *candidate = dynamic_cast<T*>(m_components[i]);
if (candidate) {
return candidate;
}
}
return nullptr;
}
Recall that dynamic_cast<T*> would return a non-null value only when the cast has been successful. The code above goes through all pointers, and picks the first one for which dynamic_cast<T*> succeeds.
Important note: While this should do the trick at making your program do what you want, consider changing your design: rather than pulling out objects by type, give them virtual functions that would let you use them all in a uniform way. It is pointless to put objects of different classes into one container, only to pull them apart at some later time. RTTI should be used as the last resort, not as a mainstream tool, because it makes your program harder to understand.
Another valid approach would be to store the individual components separately, not in a single vector, and get the vector only when you need to treat the objects uniformly.
Less important note: if nullptr does not compile on your system, replace with return 0.
There are occasions where a system would want to group derived types from a base class vector, for example, the optimisation of multithreading.
One system I cooked up uses polymorphism to create a user defined type to avoid typeid or derived_class, here is some pseudo code...
class BaseType {
public:
virtual int getType() = 0;
}
class ThisType : public BaseType {
public:
int getType() {return 1;};
}
class TypeMaster {
private:
std::vector<ThisType*> myObjects;
public:
void add(ThisType* bc){ myObjects.push_back(bc); };
}
std::map<int,TypeMaster*> masters;
std::vector<BaseType*> objects;
for(int i=0;i<objects.size();i++){
masters.find(objects[i].getType())->second.add(objects[i]);
}
You would have to do a bit of work to make a system but the rudements are there to convey the idea. This code processes an arbitary vector of base objects and appends them to the vector of its type master.
My example has a collection of execution pools with multiple instances of the type master meaning the type master cannot be polymorphed because in that scenario the object would not be able to move around execution pools.
Note the lack of use of typeid or derived class. For me, implementations using native types keeps it simple without importing bloating libraries or any unnecessary execution fuss. You could perform speed trials but I have always found simple native type implementations to be quite succinct.
I hope the headline isn't too confusing. What I have is a class StorageManager containing a list of objects of classes derived from Storage. Here is an example.
struct Storage {}; // abstract
class StorageManager
{
private:
map<string, unique_ptr<Storage>> List; // store all types of storage
public:
template <typename T>
void Add(string Name) // add new storage with name
{
List.insert(make_pair(Name, unique_ptr<Storage>(new T())));
}
Storage* Get(string Name) // get storage by name
{
return List[Name].get();
}
};
Say Position is a special storage type.
struct Position : public Storage
{
int X;
int Y;
};
Thanks to the great answers on my last question the Add function already works. What I want to improve is the Get function. It reasonable returns a pointer Storage* what I can use like the following.
int main()
{
StorageManager Manager;
Manager.Add<Position>("pos"); // add a new storage of type position
auto Strge = Manager.Get("pos"); // get pointer to base class storage
auto Pstn = (Position*)Strge; // convert pointer to derived class position
Pstn->X = 5;
Pstn->Y = 42;
}
It there a way to get rid of this pointer casting by automatically returning a pointer to the derived class? Maybe using templates?
use:
template< class T >
T* Get(std::string const& name)
{
auto i = List.find(name);
return i == List.end() ? nullptr : static_cast<T*>(i->second.get());
}
And then in your code:
Position* p = Manager.Get<Position>("pos");
I don't see what you can do for your Get member function besides what #BigBoss already pointed out, but you can improve your Add member to return the used storage.
template <typename T>
T* Add(string Name) // add new storage with name
{
T* t = new T();
List.insert(make_pair(Name, unique_ptr<Storage>(t)));
return t;
}
// create the pointer directly in a unique_ptr
template <typename T>
T* Add(string Name) // add new storage with name
{
std::unique_ptr<T> x{new T{}};
T* t = x.get();
List.insert(make_pair(Name, std::move(x)));
return t;
}
EDIT The temporary prevents us from having to dynamic_cast.
EDIT2 Implement MatthieuM's suggestion.
You can also further improve the function by accepting a value of the
type to be inserted, with a default argument, but that might incur an
additional copy.
When you have a pointer or reference to an object of some class, all you know is that the actual runtime object it references is either of that class or of some derived class. auto cannot know the runtime type of an object at compile time, because the piece of code containing the auto variable could be in a function that is run twice -- once handling an object of one runtime type, another handling an object with a different runtime type! The type system can't tell you what exact types are in play in a language with polymorphism -- it can only provide some constraints.
If you know that the runtime type of an object is some particular derived class (as in your example), you can (and must) use a cast. (It's considered preferable to use a cast of the form static_cast<Position*>, since casts are dangerous, and this makes it easier to search for casts in your code.)
But generally speaking, doing this a lot is a sign of poor design. The purpose of declaring a base class and deriving other class types from it is to enable objects of all of these those types to be treated the same way, without casting to a particular type.
If you want to always have the correct derived type at compile time without ever using casts, you have no choice but to use a separate collection of that type. In this case, there is probably no point deriving Position from Storage.
If you can rearrange things so that everything that a caller of StorageManager::Get() needs to do with a Position can be done by calling functions that don't specify Position-specific information (such as co-ordinates), you can make these functions into virtual functions in Storage, and implement Position-specific versions of them in Position. For example, you could make a function Storage::Dump() which writes its object to stdout. Position::Dump() would output X and Y, while the implementations of Dump() for other conceivable derived classes would output different information.
Sometimes you need to be able to work with an object that could be one of several essentially unrelated types. I suspect that may be the case here. In that case, boost::variant<> is a good way to go. This library provides a powerful mechanism called the Visitor pattern, which allows you to specify what action should be taken for each of the types that a variant object could possibly be.
Apart from the fact that this looks like a terrible idea... let's see what we can do to improve the situation.
=> It's a bad idea to require default construction
template <typename T>
T& add(std::string const& name, std::unique_ptr<T> element) {
T& t = *element;
auto result = map.insert(std::make_pair(name, std::move(element)));
if (result.second == false) {
// FIXME: somehow add the name here, for easier diagnosis
throw std::runtime_error("Duplicate element");
}
return t;
}
=> It's a bad idea to downcast blindly
template <typename T>
T* get(std::string const& name) const {
auto it = map.find(name);
return it != map.end() ? dynamic_cast<T*>(it->second.get()) : nullptr;
}
But frankly, this system is quite full of holes. And probably unnecessary in the first place. I encourage you to review the general problem an come up with a much better design.