Hi!
First of all, I am sorry for posting a general C++ question, but the origin of the problem made me believe that this would be the best place. I also searched the forum and web, but didn’t found satisfying solution or guideline (or I just suck at searching
).
Also bear in mind that I am inexperienced in C++, (but learning new things steadily
)
Basically, I am making use of polymorphism during drawing.
I made a abstract base class (derived from sf::Drawable and sf::Transformable) and several derived classes. The objects from derived classes are updated, but not drawn.
Then I made a special deque in which are stored raw pointers of base class. These pointers point to the objects of derived classes and are used for drawing.
So instead of writing something like this:
window.draw(object_1); // object of derived class 1;
window.draw(object_2); // object of derived class 2;
window.draw(object_3); // object of derived class 3;
window.draw(object_4); // object of derived class 4;
for (const auto& it: cont_1) // container of X objects of derived class 5;
window.draw(it);
for (const auto& it: cont_2) // container of Y objects of derived class 6;
window.draw(it);
// Now imagine that there are additional 50 more derived classes with at least one object below.
I can write it like this:
for (const auto& it: cont_of_pointers) // container of X pointers of the base class that point to objects derived classes;
window.draw(*it);
Neat!
When object is no longer useful and won’t be used any time soon. I need to delete it. Therefore, I need to delete both the pointer pointing to that object from the array and the object itself during runtime.
The deletion goes smoothly, but the program crashes when it starts drawing objects, with the message “R6025 – Pure Virtual function called”. The error seems to refer to a draw function inside sf::Drawable, which is the main reason why I posted topic on this forum.
The problem now is, what I managed to figure out, is that when I delete the object itself, the problem occurs. If I delete only the pointer, it works, but the object itself is still inside the memory and program takes him into account when dealing with logic, it is simply invisible because it is no longer being drawn.
(Maybe the lambda expression is the problem… I started using them just recently, thought I should point that out.
)
So my questions are:
1. What should I do in order to prevent the pure virtual function call in this method for drawing?
2. Should I even draw like this in the first place?
3. How is this error even possible? There are no dangling pointers nor calls to a pure virtual functions inside my base class constructor/destructor and the compiler won’t even run the program if there is a call to a pure virtual function somewhere else in the code, as far as I know.
Here is complete and minimal example that reproduces the problem:
#include "SFML\Window.hpp"
#include "SFML\System.hpp"
#include "SFML\Graphics.hpp"
#include <algorithm>
#include <deque>
// Base object
class Object : public sf::Drawable
{
public:
virtual void draw(sf::RenderTarget&, sf::RenderStates) const = 0;
bool is_deleted;
};
// Derived object
class Square : public Object
{
sf::RectangleShape square;
public:
Square(sf::Vector2f position)
{
square.setFillColor(sf::Color::Green);
square.setSize(sf::Vector2f(20, 20));
square.setPosition(position);
is_deleted = false;
}
void draw(sf::RenderTarget& target, sf::RenderStates state) const
{
target.draw(square, state);
}
};
int main()
{
sf::RenderWindow window(sf::VideoMode(800, 600), "Test", sf::Style::Default);
sf::Event eve;
// Initialising objects and putting them into containters
std::deque<Square> square_deque;
Square square_1(sf::Vector2f(100, 25));
square_deque.push_back(square_1);
Square square_2(sf::Vector2f(100, 50));
square_deque.push_back(square_2);
Square square_3(sf::Vector2f(100, 75));
square_deque.push_back(square_3);
// Seperate deque that contains pointers of base class - pointers take adresses of derived objects and are stored for later drawing.
// Doing so, I can store different types of objects into the deque who share the same parent class.
Object* ptr;
std::deque<Object*> objects_for_draw;
for (unsigned int i = 0; i < square_deque.size(); ++i)
{
ptr = &square_deque.at(i);
objects_for_draw.push_back(std::move(ptr));
}
while (window.isOpen())
{
while (window.pollEvent(eve))
{
if (eve.type == sf::Event::Closed)
window.close();
if (eve.type == sf::Event::KeyPressed)
{
if (eve.key.code == sf::Keyboard::Space)
{
// When space is pressed, the second square is marked for deletion.
// Then the object is being evaluated in lambda expression whether the 'is_deleted' bool true.
// If it is, then it's removed from both deque containters.
square_deque.at(1).is_deleted = true;
objects_for_draw.erase(std::remove_if(objects_for_draw.begin(), objects_for_draw.end(), [&](Object* param) { return param->is_deleted; }), objects_for_draw.end());
// Here is a second deque container from which the object should be removed.
// Unfortunetaly, when it is removed, the " Pure virtual function call" error occurs later.
// When this is commented out, the program runs fine - but object still exists and can interact. It is simply not drawn anymore
square_deque.erase(std::remove_if(square_deque.begin(), square_deque.end(), [&](Square param) { return param.is_deleted; }), square_deque.end());
}
}
}
window.clear(sf::Color(63,63,63,255));
for (const auto& it : objects_for_draw)
window.draw(*it); // The program breaks here (or at least the breakpoint points here), with error message "R6025 - Pure virtual function called"
window.display();
}
return 0;
}