I have two classes. The superclass is a "Component" class, and the subclass is a "Transform" class.
The framework I'm using has a function that returns a list of components of a certain type. However, the list will return them as Component, since the type isn't restricted to a specific subclass (however it's the way I'm using it).
So, in the following scenario, I know that all the returned components will be of the Transform subclass. What I'm doing is I'm iterating over the list and then casting each component to Transform. Here is my code:
std::list<Cistron::Component*,std::allocator<Cistron::Component*>> playerTransforms = objectManager->getComponents(player,"Transform");
std::list<Cistron::Component*>::iterator playerComponentIterator = playerTransforms.begin();
for (playerComponentIterator; playerComponentIterator != playerTransforms.end(); playerComponentIterator++)
{
Transform *tmpTransform = static_cast<Transform*> (*playerComponentIterator);
std::cout << tmpTransform->x ;
std::cout << tmpTransform->y ;
}
How efficient is this? I'm quite new to C++, so I have no idea if there's a better way of doing this.
This isn't a good design, your compiler should generate a warning in this case. Normally, you should upcast your pointer using dynamic_cast. This cast has some runtime cost - aproximately the same as virtual method call but it will generate exception if you try to cast incompatible pointers.
Try to redesign your app to eliminate this code. You should only call virtual methods of the Component class, you shouldn't cast pointer to Component to pointer to Transform. This thing indicate bad design.
One possible desigion is to make getComponents a template method to eliminate cast:
template<class T>
list<T*> getComponents(Player* player, std::string name) {
...
}
or maybe just this:
list<Transform*> getTransfromComponents(Player* player) {...}
In a case when you can't refactor this code, you can always transform your list:
list<Component*> rlist = ...
list<Transform*> llist;
// Upcast all
transform(rlist.begin(),
rlist.end(),
back_inserter(llist),
[](Component* r) {
return dynamic_cast<Transform*>(r);
});
// Remove all null values
llist.remove(nullptr);
The std::list is usually implemented as double-linked list, which means that elements are scattered through the memory, which means that iterating through it is slow. Check: Why is it so slow iterating over a big std::list?
But what I would worry more about is the use of reflection:
objectManager->getComponents(player,"Transform");
that might actually be the real bottleneck of this piece of code.
Related
I'm doing a program that has a different kind of objects and all of them are children of a virtual class. I'm doing this looking for the advantages of polymorphism that allow me to call from a manager class a certain method of all the objects without checking the specific kind of object it is.
The point is the different kind of objects need sometimes get a list of objects of a certain type.
In that moment my manager class loop thought all the objects and check the type of the object. It creates a list and return it like this:
std::list<std::shared_ptr<Object>> ObjectManager::GetObjectsOfType(std::string type)
{
std::list<std::shared_ptr<Object>> objectsOfType;
for (int i = 0; i < m_objects.size(); ++i)
{
if (m_objects[i]->GetType() == type)
{
objectsOfType.push_back(m_objects[i]);
}
}
return objectsOfType;
}
m_objects is a deque. I know iterate a data structure is normally expensive but I want to know if is possible to polish it a little bit because now this function takes a third of all the time used in the program.
My question is: is there any design pattern or fuction that I'm not taking into account in order to reduce the cost of this operation in my program?
In the code as given, there is just a single optimization that can be done locally:
for (auto const& obj : m_objects)
{
if (obj->GetType() == type)
{
objectsOfType.push_back(obj);
}
}
The rationale is that operator[] is generally not the most efficient way to access a deque. Having said that, I don't expect a major improvement. Your locality of reference is very poor: You're essentially looking at two dereferences (shared_ptr and string).
A logical approach would be to make m_objects a std::multimap keyed by type.
Some things you can do to speed up:
Store the type on the base class, this will remove a somewhat expensive virtual lookup.
If type is a string, etc. change to a
simpel type like an enum or int
A vector is more effiecient to
traverse than a deque
if staying with deque, use iterators or a range based for loop to avoid the random lookups (which are more expensive in deque)
Range based looks like this:
for (auto const& obj : m_objects)
{
if (obj->GetType() == type)
{
objectsOfType.push_back(obj);
}
}
Update: Also I would recommend against using a std::list (unless for some reason you have to) as it is not really performing well in many cases - again std::vector springs to the rescue !
I have a for each loop which iterates over a vector of pointers. the pointers are to a base class. In the for each loop I use the derived type as the type for the iterator. The render function is only defined in some of the derived classes, yet the code compiles and runs... It crashes if the vector contains a pointer to a derived object which doesn't have the render function (obviously).
for each (DerivedClass* body in myVector)
{
body->render();
}
This error came about in my code because when I wrote it the vector only contained pointers to the derived class but later on I decided to refactor the code and this changed.
Can anyone tell me the right way to trap this error? Checking for a null pointer doesn't seem to work.
Really, the problem here is that Microsoft's foreach loop is too permissive. Microsoft has deprecated this extension in favour of the standard range-based for loop (since C++11):
for (DerivedClass* body : myVector) {
body->render();
}
Here, the head of the loop, won't compile because it cannot initialize a DerivedClass* from a BaseClass*.
Regarding actually getting this to compile, firstly, please rethink your design. You should be programming to interfaces, not to implementations. Having to rely on these objects being renderable when some aren't is a code smell. That said, it's possible through dynamic_cast:
for (auto base : myVector) {
if (auto derived = dynamic_cast<DerivedClass*>(base)) {
derived->render();
}
}
Don't have C++11 (which I can only assume from the lack of the standard loop)? You can still use a traditional for loop with indices or iterators. You can also be more explicit about the types in my dynamic_cast example.
To add a little spin, sometimes it does come up where this type of casting is common (e.g., some compiler implementations). If this is determined to be a good design choice, you can wrap this code in an algorithm. For example, here's how it looks in C#:
foreach (var body in myVector.OfType<DerivedClass>()) {
body.render();
}
If I understand you correctly, the problem is that only some of the pointers in your vector point to objects that are of a type that implements render(). If that's the case dynamic_cast will do the trick of checking for the right type.
for (DerivedClass *p : myVector) {
class_implementing_render *q = dynamic_cast<class_implementing_render>(p);
if (q) q->render();
}
Suppose I have this setup:
struct XView;
struct X
{
...
XView view;
};
Type XView is only used for this one field; it is internal too, so instantiating it from outside, i.e. using it for anything else is prohibited.
So, assuming any object of XView type is an X::view field, is it possible to find address of X from address of XView, staying fully within behavior defined by C++ standard and without type-punning? I.e. is it possible to do something like this:
void XView::some_function ()
{
X& this_x = some_computations_involving (this);
}
I can of course store a pointer, so this would become as trivial as x = *this->parent_x, but would like to do without one if possible.
EDIT: Note that I need an answer without type-punning involved, otherwise I'd rather use that "just store a pointer" solution.
First approach is to make XView the first member of X, then you can do this:
void XView::some_function ()
{
X & this_x = reinterpret_cast<X&>(*this);
}
Second approach is to use offset when XView is not the first member of the X.
Techinically speaking both of these approaches are same if there is no virtuality involved, only that the first approach is a special case (i.e when offset = 0) of the second approach which is the general case.
As for the edit, I think, without casting it is not possible. You have to store the pointer in XView, Or maintaining a map (or some other data structures) of pointers.
The most important thing is whether you really need accessing the parent object from child object and not vice-versa.
I would suggest you using some kind of bi-directional linked list or something like this.
Could your code be refactored to be more object-oriented? (and possibly using the inheritance (and calling the parent by using the super::some_function...)
I'm currently writing WinRT code, but I imagine this question applies to all C++. Upon user interaction, the framework calls one of my functions passing in a vector with generic Object^ pointers (very similar to void* for you non-WinRT folks). I already know what type of objects are in the vector and I'd like to cast the vector to that object type.
Example:
MyClass::SomeFunction(Vector<Object^>^ myList) {
// Warning: The following line doesn't work!!
Vector<SpecificType^>^ myTypedList = static_cast<Vector<SpecificType^>^>(myList);
// Here, I go on to interact with the templated vector.
...
}
The compiler doesn't allow me to use static_cast. safe_cast throws an exception. dynamic_cast doesn't throw an exception, but returns a null pointer.
Is there a way I can cast this thing, or do I literally have to create a new vector and copy all the members over (casting each from Object^ to SpecificType^ on insertion)?
You cannot cast Vector<Object^> to any other Vector<> because there is no inheritance involved between them. The only thing that you can do is cast each element into the right class. So, if you want a Vector<SpecificType^> you do indeed need to create it anew. Not that it is too hard:
Vector<SpecificType^> specificList;
for (Object^ p : myList)
specificList.push_back(static_cast<SpecificType^>(p));
Here is my issue:
In my GUI, there are several types of listeners. They are stored in std::vector<WhateverListener*>
In my GUI, I have a method called removeListeners and it looks like this:
void Widget::removeListeners( Widget* widget )
{
removeFocusListener((FocusListener*)widget);
removeMouseListener((MouseListener*)widget);
removeKeyboardListener((KeyboardListener*)widget);
removeWidgetListener((WidgetListener*)widget);
}
Basically, I do not think it should matter how I cast it; they are just pointers. I think std::remove simply compares pointers, therefore if I provide a widget* then it shouldn't affect anything (I think).
How the remove functions look is something like this:
void Widget::removeWidgetListener(
WidgetListener *listener )
{
widgetListeners.erase(
std::remove(widgetListeners.begin(),
widgetListeners.end(), listener),
widgetListeners.end());
}
So, in the Widget destructor, I iterate through the widget's children and call removeListeners():
Widget::~Widget(void)
{
for(std::vector<Widget*>::iterator it = getChildBegin();
it != getChildEnd(); ++it)
{
(*it)->removeListeners(this);
(*it)->parentWidget = NULL;
(*it)->_container = NULL;
}
}
It does not work. After calling delete on a Widget which was listening to its children, the children still had listeners.
However, if I call the remove methods directly, and the widget inherits from the listener, it works:
Widget::~Widget(void)
{
for(std::vector<Widget*>::iterator it = getChildBegin();
it != getChildEnd(); ++it)
{
(*it)->removeWidgetListener(this);
(*it)->parentWidget = NULL;
(*it)->_container = NULL;
}
}
So why does one work and not the other? The only difference I spot is that in the first one I'm casting a Widget to that type. But I thought it would just compare pointers and if they were == it would remove it?
I'm afraid you might be getting stung by object identity and virtual base classes in C++
http://www.parashift.com/c++-faq-lite/multiple-inheritance.html
Basically, converting pointers to polymorphics bases, is not guaranteed to result in identical pointer values (when cast to (void*) e.g.).
It should work as long as you store the exact same pointer type as what you cast it to during removal, but I can't be sure without looking at more of your code/widget class hierarchy.
The root of your issue seems to be an incorrect design. The need to cast as you are doing implies that the function is in the wrong place. It's not clear from your post what the relationship between Widgets and the different types of Listener classes are.
You need to rethink where you are calling the removeListeners function from and instead of putting it in the base class destructor, you should put it in the destructor of the class that actually knows which type of listener it is (and only call the correct one).
It's hard to be more specific without getting some more detail on the relationships between your classes. In general, if you have to cast, you should ask yourself if there is a better way to accomplish what it is that's forcing you to cast.