-1

So, i was trying to make a 2d game with opengl and sfml, so i created a button class in an input namespace, i made a render() function in it, but when i call it (no matter wheter i use a pointer or i don't) even if I pass all the required arguments it's still giving me an error, saying that I'm trying to access a deleted function here's the Button header:

#pragma once

#include <SFML/Graphics.hpp>
#include "InputManager.h"

namespace input {

class Button {
private:
    bool m_Selected, m_Clicked;
    sf::Vector2f m_Position;
    sf::Sprite m_Sprite;
    sf::Texture m_Texture;
public:
    Button(sf::Vector2f position, sf::Sprite sprite);
    Button(sf::Vector2f position, sf::Texture texture);
    Button(sf::Vector2f position);
    Button();
    ~Button();
    void update(engine::InputManager inputManager);
    void render(sf::RenderWindow window);
    inline bool isClicked() { return m_Clicked; }
    inline bool isSelected() { return m_Selected; }
    inline sf::Vector2f getPosition() { return m_Position; }
    void setPosition(sf::Vector2f position) { m_Position = position; }
};

}

here is Button.cpp:

#include "Button.h"

namespace input {

Button::Button(sf::Vector2f position, sf::Sprite texture) : m_Position(position), m_Sprite(texture) {
    m_Sprite.setPosition(m_Position);
}

Button::Button(sf::Vector2f position, sf::Texture texture) : m_Position(position), m_Texture(texture) {

    m_Sprite.setTexture(m_Texture);
    m_Sprite.setPosition(m_Position);
}

Button::Button(sf::Vector2f position) : m_Position(position) {
    m_Sprite.setPosition(m_Position);
}

void Button::update(engine::InputManager inputManager) {}

void Button::render(sf::RenderWindow window) {
    window.draw(m_Sprite);
}

Button::~Button() {
    delete &m_Position;
    delete &m_Texture;
    delete &m_Clicked;
    delete &m_Selected;
}
}

Here is the main.cpp code:

#include <iostream>
#include <vector>
#include "InputManager.h"
#include "Button.h"

#define WIDTH 800
#define HEIGHT 600
#define TITLE "C++ Platformer"

int main() {

sf::RenderWindow window(sf::VideoMode(WIDTH, HEIGHT), TITLE, sf::Style::Close | sf::Style::Titlebar);

sf::Texture ButtonTexture;
ButtonTexture.loadFromFile("Texture.png");
sf::Sprite sprite;
sprite.setTexture(ButtonTexture);

input::Button* button = new input::Button(sf::Vector2f(100.f, 100.f), sprite);

int fps = 0;

int ticks = 0;

sf::Clock clock;
sf::Clock FpsClock;
sf::Time time;
sf::Time Fpstime;

long delta = 0;
long target = 1000000 / 60;

engine::InputManager IManager;

sf::Event ev;
while (window.isOpen()) {
    while (window.pollEvent(ev)) {
        if (ev.type == sf::Event::Closed) window.close();
        if (ev.key.code == sf::Keyboard::Escape) window.close();
        if (ev.type == sf::Event::KeyPressed) IManager.onKeyDown(ev.key.code);
    }
    time = clock.getElapsedTime();
    if (target > time.asMicroseconds()) {
        clock.restart();
        // UPDATE
        button->update(IManager);

        delta = time.asMicroseconds() % 60;
        target = 1000000 / 60 + delta;
        ticks++;
    } Fpstime = FpsClock.getElapsedTime();
    if (Fpstime.asSeconds() >= 1) { 
        std::cout << "FPS: " << fps << " Ticks: " << ticks << std::endl; 
        FpsClock.restart();
        fps = 0;
    }
    fps++;
    // RENDER
    button->render(window);
}

return EXIT_SUCCESS;
}

I've searched on microsoft docs and on other stackoverflow questions, but i couldn't find any case like mine, hope someone can help, thanks

Chappie733
  • 45
  • 6
  • Please include the full error message – 463035818_is_not_an_ai Mar 21 '19 at 19:06
  • Please add the complete error message of the compiler to your post. – R Sahu Mar 21 '19 at 19:06
  • 3
    Base class of `sf::RenderWindow` is `sf::Window` which is derived from `NonCopyable`. You cannot pass `RenderWindow` by value into `Button::render`. Look at [diagram](https://www.sfml-dev.org/documentation/2.5.1/classsf_1_1NonCopyable.php). Use references. – rafix07 Mar 21 '19 at 19:08
  • 2
    Not the problem but your destructor is going to crash your program. You only call `delete` on things you call `new` on. You don't call `new` on the class members so you should not be calling `delete` on them. – NathanOliver Mar 21 '19 at 19:08
  • 3
    I really can't emphasize it enough. Do not make your first program a game using sfml! It is just too much to digest! Learn to program in C++ using easier topics, like may be text processing or small data manager or something like that. Try implementing a scientific calculator or something else which would not expose to you to complexities of a huge and involved library. Basically, you need to learn how to swim before practicing diving - even though diving might be way more fun. – SergeyA Mar 21 '19 at 19:22
  • Please stop with the manual memory management nonsense. Especially doing it very wrong as you currently do. That destructor of yours is just .. I'll just say, bad .. – Jesper Juhl Mar 21 '19 at 19:26

2 Answers2

3

First of all. what the...

Button::~Button() {
    delete &m_Position;
    delete &m_Texture;
    delete &m_Clicked;
    delete &m_Selected;
}

You shouldn't do that.

But back to your error. It is quite descriptive. You are trying to use a function that was most likely deleted explicitly. Like so:

struct Test {
    Test(const Test & other) = delete; 
};

Obviously I cannot copy Test now because I deleted the copy constructor.

Which is what sf::RenderWindow does by inheriting from sf::NonCopyable class.

And since your render() method takes it by copy and not reference. It obviously tries to do something it was forbidden.

You should change from this:

void Button::render(sf::RenderWindow window)

To this:

void Button::render(sf::RenderWindow & window)
SLC
  • 2,167
  • 2
  • 28
  • 46
3

The problem is that sf::RenderWindow is non-copyable. This is a good thing, because it means that you can't accidentally get confused about having multiple windows, and it's clear when you create a new window and where it is owned. However, in a function signature like

void Button::render(sf::RenderWindow window);

you are accepting an sf::RenderWindow by value. This means that whenever you call Button::render and pass a window, that window is copied before it is received by the function. See the problem?

You need to accept the render window by reference, to make sure you don't try to create a copy:

void Button::render(sf::RenderWindow& window);

Aside: as pointed out by NathanOliver, you try to delete all of your instance members in your Button destructor, even though they are not pointers, and you didn't specifically allocate them with new. Only delete what you new, and avoid new/delete altogether if you can.

If you're unsure about what it means to pass by reference, or what new and delete are for, I would suggest you pick up a copy of a good C++ book.

alter_igel
  • 6,899
  • 3
  • 21
  • 40