C++ - passing smart pointer derived class - c++

I have a class Character that inherits from a base class CollidableObject. CollidableObject has, as you may have guessed, methods to detect collisions between other CollidableObjects, such as CircleCollidableObject and SquareCollidableObject.
bool CollidableObject::collidesWith(std::shared_ptr<CollidableObject> &pCollidable)
{
...
}
I use this to run other checks, and eventually handle the collision. Basically I want to be able to loop through the characters in my game, pass in two Characters (that, again, inherit from CollidableObject), and detect any collisions.
void CharacterManager::collisions()
{
for(std::vector<std::shared_ptr<Character>>::iterator i = mCharacters_.begin(); i != mCharacters_.end(); i++) {
for(std::vector<std::shared_ptr<Character>>::iterator j = mCharacters_.begin(); j != mCharacters_.end(); j++) {
if(i == j) continue;
(*i)->collidesWith(*j);
...
}
I'd rather not make the mCharacters_ vector into a vector of CollidableObjects if I dont have to. But I'm not sure if that's the only way.

Can you rewrite the interface? There's nothing wrong with having:
bool CollidableObject::collidesWith(const CollidableObject* pCollidable)
Presumably collidesWith isn't going to take ownership of the pointer you pass in, so passing in a raw pointer is fine.
That said, shared_ptr<CollidableObject> is actually constructible from shared_ptr<Character>. So if you want to take a shared_ptr, you'll have to take it by const reference instead of by reference. That is:
bool CollidableObject::collidesWith(const std::shared_ptr<CollidableObject>& p)
or just by-value:
bool CollidableObject::collidesWith(std::shared_ptr<CollidableObject> p)
See constructor #9 from this reference.
And if you're using std::shared_ptr, you should at least use auto in your loops to reduce the verbosity. And the j loop can start one-past i to avoid double-checking every pair:
for (auto i = mCharacters_.begin(); i != mCharacters_.end(); ++i) {
for (auto j = std::next(i); j != mCharacters_.end(); ++j) {
(*i)->collidesWith(j->get());
...
}
}

Related

How to erase a certain element from a shared_ptr to a vector of objects?

I have created a member variable (in the class Group) that is a shared_ptr to a vector (called members that stores objects of type User (a different class). Here is the member variable definition (empty):
std::shared_ptr <std::vector<User>> members = std::make_shared<std::vector<User>>();
To eliminate a certain User object from the vector (members), I created a member function (remove) inside the class Group. It checks all the User objects inside the vector and, when encounters the one with the a.URI value that is looking for, it erases the object at that location in the vector.
void Group::remove(User a) {
for (auto i = 0; i < members->size(); i++){
if (a.URI == (*(members->begin()+i)).URI) members->erase(*(members->begin() + i));
}
That is my remove function by now, but it doesn't work. I have checked different configurations but can`t make it work. Is there a problem with my function? How should this function be implemented (special rules for shared_ptr?)? Is there a better/optimal way?
I think no more code is needed here to solve my question. However, for those who want a MCV example, I tried to write one here (Ideone).
Firstly, std::vector::erase expects an iterator as its argument, so change
members->erase(*(members->begin() + i))
to
members->erase(members->begin() + i)
Secondly, after the element being erased, when i++ is evaluated, you will skip the next element or get out of the bound of the vector. You might change the loop to
for (auto i = 0; i < members->size(); ) {
if (a.URI == (*(members->begin()+i)).URI)
members->erase(members->begin() + i);
else
i++;
}
Why don't you declare the vector members as static member of the group class. I did it like this:
#include <bits/stdc++.h>
using namespace std;
class User{
public:
int URI;
User(int a){
URI = a;
}
};
class Group {
public:
static vector<User> members;
void remove(User a) {
for (int i = 0; i < members.size();){
if (a.URI == (*(members.begin()+i)).URI) members.erase((members.begin() + i));
else
i++;
}
}
Group(User a, User b, User c){
members.push_back(a);
members.push_back(b);
members.push_back(c);
}
};
vector<User> Group::members;
int main() {
User a(1), b(2), c(3);
Group obj(a, b, c);
obj.remove(a);
return 0;
}
Hope it helps.

Cannot carry object to function properly C++

cliques is my class object. All my class commands work when I use them in my main but for some reason I cannot make changes to my heaps or stacks through my functions. I tried using reference markers on my function parameters but still I'm having ussues. Maybe I've done the reference incorrectly. Does anyone have any ideas what I might be doing wrong?
This is one of my functions:
void UpdateTopK(cliques C, vector<cliques> minheap) {
if (C.getclique_size() < CliqueSize) {
return;
}
else if (minheap.size() < Solutions) {
minheap.push_back(C);
push_heap(minheap.begin(), minheap.end(), min_iterator());
}
else if (minheap.size() == Solutions and C.getMaxclique_prob() > minheap.front().getMaxclique_prob()) {
pop_heap(minheap.begin(), minheap.end(), min_iterator());
minheap.pop_back();
minheap.push_back(C);
push_heap(minheap.begin(), minheap.end(), min_iterator());
}
This is part of my main:
stack <cliques> cstack;
vector<cliques> max_heap;
make_heap(max_heap.begin(), max_heap.end(), max_iterator());
vector<cliques> min_heap;
make_heap(min_heap.begin(), min_heap.end(), min_iterator());
for (int i = 0; i < 5; i++) {
cliques temp(i);
cstack.push(temp);
}
while (!cstack.empty()) {
cliques temp = cstack.top();
cstack.pop();
bool pruned = GenerateChildren(temp, min_heap, max_heap, cstack, graph);
if (!pruned) {
UpdateTopK(temp, min_heap);
}
}
You are passing arguments by value, this implies that parameters are copied before being passed to the function.
So every modification inside a method refers to the local copy only. Try passing values by references, eg:
void UpdateTopK(cliques& C, vector<cliques>& minheap)
^ ^
Mind that an object that needs to be passed to a function without copy and without being edited should be passed by const T& to specify this.

Best way to iterate through a for loop, and then iterate through it again backwards?

I found that when writing animations I sometimes run into having to go through a for loop once, then iterate the value down afterwards. This was generally used for jump animations, or disappear then appear again animations.
Here's an example of what I had done -
// Make the sprite slowly disappear
for (int i = 256; i > 0; --i)
{
sprite.opacity(i);
draw();
}
// Make the sprite slowly appear again
for (int i = 0; i < 256; ++i)
{
sprite.opacity(i);
draw();
}
Every time I did this I had a deep feeling that it was too much. What would be a nicer way of going about this? I'm not entirely sure what would be best practice. I imagine I could use reverse_iterator, but I'm also not sure how I would implement it.
Consider the use of <cmath> abs() function:
for( int i = -255; i <= 255; i++)
use( abs( i ) );
You can use the absolute value function abs() defined in <cmath>. It will halve the code written in your case.
for(int i=0; i<512; ++i)
{
sprite.opacity( abs(256-i) );
draw();
}
I believe in the situation you are describing, you have to iterate through the sprites to set the opacity of each sprite. Whether you use a for loop, or a reverse_iterator, the time spent is going to be the same. Any implementation of the reverse_iterator will still have to iterate through each sprite. There might be ways to make it easier to read, but in the end the algorithm will come down to the same. For example, you could take advantage of the stack and call the sprites recursively to increase the opacity and then decrease on the way back out; however, I see no gain in doing so the algorithm time would still end up being the same.
In some cases, you just need to bite the bullet and spend the time doing things in a way that may seem like (or even be) brute force.
That's a great way to iterate through a loop both forward and "in reverse" - one commonly used by C++ programmers.
For your sprite, it appears that the 256 range (you might consider setting a const int RGB_RANGE equal to 256 - or a more appropriate identifier) is all that is needed; however, were the size of your object dynamic, you could also consider using the .size() function (something like an ArrayList or a vector - here is where something like an iterator would be useful):
for (i = 9; i < RGB_RANGE; i++)
{
// CODE
}
The above code being an example of the first const suggestion. Remember, simple code is never a bad thing - it means you are doing something right.
If you don't want to use abs, I'd go with something like :
template<typename Func>
void animate (size_t step_count, Func && f)
{
size_t step;
for (step = step_count ; step > 0 ; --step)
f(step - 1);
for (step = 1 ; step < step_count ; ++step)
f(step);
}
Use case :
animate(256, [](size_t step)
{
sprite.opacity(step);
draw();
});
If you wish to just iterate a range up and down again, you can go the very crazy route and just define a "container" (or range, in boost lingo) that provides iterators (well, technically they are more almost-iterators) which allow you to express exactly what you intend to do:
for(auto i : down_and_up(3)) ::std::cout << i << "\n";
For example should print
3
2
1
0
1
2
Sadly, there is not much support in the standard library for types like this, although boost provides boost::iterator_range, boost::counting_iterator, and boost::join that, in concert with std::reverse_iterator, can provide down_and_up. Writing one yourself if fairly simple (although verbose), as long as you do not completely abuse it:
struct down_and_up
{
size_t from;
down_and_up(size_t const from) : from(from) { }
struct iterator : public ::std::iterator<::std::forward_iterator_tag, size_t> {
size_t cur;
bool down;
iterator(size_t cur, bool down) : cur(cur), down(down) { }
size_t operator*() const { return cur; }
iterator& operator++()
{
if(down)
{
--cur;
if(0 == cur) down = false;
}
else ++cur;
return *this;
}
friend bool operator==(iterator const& lhs, iterator const& rhs) { return lhs.down == rhs.down && lhs.cur == rhs.cur; }
friend bool operator!=(iterator const& lhs, iterator const& rhs) { return lhs.down != rhs.down || lhs.cur != rhs.cur; }
};
iterator begin() const { return iterator{ from, true }; }
iterator end() const { return iterator{ from, false }; }
};
Note: If you wish, you can easily extend it with more container capabilities, like a value_type member typedef, but this definition is enough for the above example.
P.S.: The boost way, for your entertainment:
boost::iterator_range<boost::counting_iterator<size_t>> up(boost::counting_iterator<size_t>(0), boost::counting_iterator<size_t>(3));
boost::iterator_range<std::reverse_iterator<boost::counting_iterator<size_t>>> down(
std::reverse_iterator<boost::counting_iterator<size_t>>(boost::counting_iterator<size_t>(4)),
std::reverse_iterator<boost::counting_iterator<size_t>>(boost::counting_iterator<size_t>(1)));
for(auto i : boost::join(down, up)) ::std::cout << i << "\n";

Are there reasons to skip the initialization of the for loop?

For instance,
int i = 0;
for( ; i < 5; ++i )
{
doStuff();
}
Versus
for( int i = 0; i < 5; ++i )
{
doStuff();
}
The only time I have seen the first method is when the variable to be initialized is a really long named iterator. Is there anything performance wise that would make one more beneficial? Or is it merely choice and readability?
One reason you might do this is because you need to know the value of the iterator/index after the loop has ended. That doesn't really make sense with your example, because you know the value will be 5, but sometimes you do not know this in advance. Consider:
int i = 0;
for(; isStillOkay(i); ++i )
{
doStuff();
}
// now we can use the final value of i for something
In general, the only reason you could have to do this is to make sure the iterator/index is available in the enclosing scope. If you don't need that, all you are doing is polluting that scope. As always, the advice is to give all objects the smallest scope necessary.
If you have long types, I recommend you use auto to deduce the types for you. If you don't have C++11 support, I then recommend the following formatting:
for (std::some::very_long<type>::name iterator_name = some_big_initializer;
iterator_name < complicated && condition != iterator_name;
++iterator_name)
{
// ...
}
No need for initialization when you have a good reason for an infinite loop:
bool run(){
for(;;){
if(ERROR)
break;
}
}

dynamic cast from array in c++

I have a class STSequencer which extends ofxDTanbileBase.
I have a method which returns a vector<ofxDTanbileBase> based on the className i give.
I want to cast back to STSequencer but i get the following errors:
'ofxDTangibleBase *' is not a class
Dynamic_cast from rvalue to reference type 'STSequencer &'
This is how i try atm:
vector<ofxDTangibleBase> sequencers = gTangibleList->findTangibleByClassName("STSequencer");
for (int i = 0; i < sequencers.size(); i++) {
STSequencer &sequencer = dynamic_cast<STSequencer&>(&sequencers[i]);
}
This is the method:
vector<ofxDTangibleBase> ofxDGlobalTangibleList::findTangibleByClassName(const char *className) {
vector<ofxDTangibleBase> returnVector;
for (int i = 0; i < _tangibles.size(); i++) {
ofxDTangibleBase &t = _tangibles[i];
if (t.className == className) {
returnVector.push_back(t);
}
}
return returnVector;
}
A better way is also welcome.
STSequencer &sequencer = dynamic_cast<STSequencer&>
should be
STSequencer *sequencer = dynamic_cast<STSequencer*>
or else remove the & in front of sequencers[i]. By taking the address of sequencers[i], you have a pointer. But you are then trying to dynamic_cast to a reference, and that's not meaningful.
There are other risks if your design. You might end up copying (and slicing) elements when you don't expect it. I'm not sure what you're doing. For this answer, I just looked at the line that failed to compile.
Your vector does not actually contain STSequencer objects, so that cast will lead to undefined behavior, even after you fix the levels of indirection (reference vs pointer) problem.
If you really need polymorphism, you'll need to store addresses in the vector, not objects, because the vector makes assumptions about the size of its elements.
Try std::vector<std::unique_ptr<ofxDTanbileBase>>.