Partage
  • Partager sur Facebook
  • Partager sur Twitter

a

Sujet résolu
7 avril 2023 à 15:31:25

a

-
Edité par 238 7 juillet 2024 à 11:32:39

  • Partager sur Facebook
  • Partager sur Twitter
7 avril 2023 à 15:55:55

std::vector shapes;

Tes objects sont déjà managé par le le vector. Si tu prend un pointeur sur un objet puis que tu le mets dans un smart pointer, ton objet va être managé 2 fois.

238 a écrit:

Par ailleurs, sommes nous d'accord pour dire qu'ici, le pointeur nu ne représente aucun risque, étant donné qu'aucune allocation dynamique n'est effectuée ? 

En termes de gestion des objets Shape, non, les pointeurs nus ne présentent pas de risque.

Par contre, il ne faut jamais oublier qu'une indirection (pointeur, reference, iterateur, etc) sur un element d'un vector peut être invalidé si la taille du vector est changé (par exemple si tu ajoutes des élements). Donc c'est pas safe à 100% non plus.

Ici, plutôt que d'utiliser un pointeur nu, tu peux utiliser un itérateur. En pratique, c'est pareil qu'un pointeur nu en terme de sécurité, mais ça permet d'ajouter une sémantique "c'est une indirection sur un conteneur d'objets".

  • Partager sur Facebook
  • Partager sur Twitter
7 avril 2023 à 17:00:12

En compilant ton code, j'ai eu un conflit sur le nom random.  Ai changé celui du namespace en rnd.

A l'exécution, on obtient

$ ./a
double free or corruption (out)
Abandon

Il y a des protestations dans les boucles à cause de la comparaison signé/non signé

a.cc: Dans la fonction « int main() »:
a.cc:55:34: attention: comparaison d'expressions entières de types signés différents: « int » et « std::vector<Shape>::size_type » {aka « long unsigned int »} [-Wsign-compare]
   55 |                 for(int i = 0; i < shapes.size(); ++i){
      |                                ~~^~~~~~~~~~~~~~~
a.cc:77:26: attention: comparaison d'expressions entières de types signés différents: « int » et « std::vector<Shape>::size_type » {aka « long unsigned int »} [-Wsign-compare]
   77 |         for(int i = 0; i < shapes.size(); i++){
      |                        ~~^~~~~~~~~~~~~~~

La seconde boucle peut - avec profit - être remplacée par

for (auto &shape : shapes) {
       window.draw(shape.rect);  
}


Pour la première, si on passe par les indices, ben, pourquoi ne pas s'en servir pour désigner la forme sélectionnée ?

Dans un optional<int> pour faire bien,  qui remplacera aussi le booléen

  std::optional<unsigned int> selected_shape_index;

    while (window.isOpen()) {
        sf::Event event;
        while (window.pollEvent(event)) {
            if (event.type == sf::Event::Closed) {
                selected_shape_index.reset();
                window.close();
            }

            if(event.type == sf::Event::MouseButtonPressed) {
                for(unsigned int i = 0; i < shapes.size(); ++i) {
                    if(shapes[i].rect.getGlobalBounds().contains(sf::Mouse::getPosition(window).x, sf::Mouse::getPosition(window).y)) {
                           selected_shape_index = i;

                    }
                }
            }

            if(event.type == sf::Event::MouseButtonReleased) {
                selected_shape_index.reset();
            }
        }

        if(selected_shape_index.has_value()) {
            shapes[selected_shape_index.value()].setPosition(
                sf::Mouse::getPosition(window).x,
                sf::Mouse::getPosition(window).y);
        }

        window.clear(sf::Color(125, 125, 125, 255));

        for (auto &shape : shapes) {
            window.draw(shape.rect);
        }

        window.display();


--

Ceci dit, j'imagine que très bientôt, il y aura du polymorphisme sur les shapes, donc on aura un vecteur de pointeurs (intelligents) vers des shapes, pas un vecteur de shapes.

Un pas pour aller dans cette direction

    std::vector<std::unique_ptr<Shape>> shapes;
    for(int i = 0; i < 10; i++) {
        shapes.push_back(std::make_unique<Shape>());
    }

    sf::RenderWindow window(sf::VideoMode(WIN_WIDTH, WIN_HEIGHT), "Drag and drop");
    window.setFramerateLimit(60);

    Shape* selected_shape = nullptr;
    
    while (window.isOpen()) {
        sf::Event event;
        while (window.pollEvent(event)) {
            if (event.type == sf::Event::Closed) {
                window.close();
            }

            if(event.type == sf::Event::MouseButtonPressed) {
                for(auto & ptr : shapes) {

                    if(ptr->rect.getGlobalBounds().contains(
                        sf::Mouse::getPosition(window).x, 
                        sf::Mouse::getPosition(window).y)) {
                           selected_shape = ptr.get();
                    }
                }
            }

            if(event.type == sf::Event::MouseButtonReleased) {
                selected_shape = nullptr;
            }
        }

        if(selected_shape) {
            selected_shape->setPosition(
                sf::Mouse::getPosition(window).x,
                sf::Mouse::getPosition(window).y);
        }

        window.clear(sf::Color(125, 125, 125, 255));

        for (auto &ptr : shapes) {
            window.draw(ptr->rect);
        }

        window.display();
    }

Avec

  • shapes qui est le propriétaire unique de toutes les shapes
  • des pointeurs nus pour référencer une shape existante.

Ou, si il peut y avoir des co-propriétaires pour les objets, on partage

   
    std::vector<std::shared_ptr<Shape>> shapes;
    for(int i = 0; i < 10; i++) {
        shapes.push_back(std::make_shared<Shape>());
    }

    sf::RenderWindow window(sf::VideoMode(WIN_WIDTH, WIN_HEIGHT), "Drag and drop");
    window.setFramerateLimit(60);

    std::shared_ptr<Shape> selected_shape;

    while (window.isOpen()) {
        sf::Event event;
        while (window.pollEvent(event)) {
            if (event.type == sf::Event::Closed) {
                window.close();
            }

            if(event.type == sf::Event::MouseButtonPressed) {
                for(auto & ptr : shapes) {

                    if(ptr->rect.getGlobalBounds().contains(
                        sf::Mouse::getPosition(window).x, 
                        sf::Mouse::getPosition(window).y)) {
                           selected_shape = ptr;
                    }
                }
            }

            if(event.type == sf::Event::MouseButtonReleased) {
                selected_shape.reset();
            }
        }

        if(selected_shape) {
            selected_shape->setPosition(
                sf::Mouse::getPosition(window).x,
                sf::Mouse::getPosition(window).y);
        }

        window.clear(sf::Color(125, 125, 125, 255));
        for (auto &ptr : shapes) {
            window.draw(ptr->rect);
        }
        window.display();
    }





-
Edité par michelbillaud 7 avril 2023 à 18:54:01

  • Partager sur Facebook
  • Partager sur Twitter
11 avril 2023 à 19:27:48

a

-
Edité par 238 7 juillet 2024 à 11:32:51

  • Partager sur Facebook
  • Partager sur Twitter
7 juillet 2024 à 13:01:56

Bonjour, on n'efface pas ses messages après avoir reçu de l'aide je recopie le message d'origine pour archive et ferme ce sujet.

238 a écrit:

 Bonjour,

Je suis en train d'écrire une fonction de drag and drop en SFML, et qui fonctionne parfaitement avec le pointeur classique "selected_shape".

Afin de respecter les bonnes pratiques, j'ai décidé de commenter mes deux lignes qui fonctionnent et de passer en mode pointeur intelligent. Le programme compile parfaitement et j'arrive même à bouger un premier cube avec ma souris à l'écran.

Par contre lors de la seconde tentative - dans la même session - le programme plante.

Voici mon code : (lignes 42 et 58)

#include <iostream>
#include <vector>
#include <memory>
#include <random>
#include <SFML/Graphics.hpp>
 
namespace random{
    std::mt19937 mt{}; // Instantiate a 32-bit Mersenne Twister
    std::uniform_int_distribution<> unif_rand{ 50, 750 };
}
 
class Shape{
    private:
        int _SIZE { 50 };
    public:
    sf::RectangleShape rect;
    Shape(){
        rect.setSize(sf::Vector2f(_SIZE, _SIZE));
        rect.setOrigin(static_cast<int>(_SIZE / 2), static_cast<int>(_SIZE / 2));
        rect.setFillColor(sf::Color::Green);
        rect.setPosition(random::unif_rand(random::mt), random::unif_rand(random::mt));
    }
    void setPosition(int x, int y){
        rect.setPosition(x, y);
    }
};
 
int main()
{
    constexpr unsigned int WIN_WIDTH    { 800 };
    constexpr unsigned int WIN_HEIGHT   { 800 };
 
    std::vector<Shape> shapes;
    for(int i = 0; i < 10; i++){
        shapes.push_back(Shape());
    }
 
    sf::RenderWindow window(sf::VideoMode(WIN_WIDTH, WIN_HEIGHT), "Drag and drop");
    window.setFramerateLimit(60);
 
    //Shape* selected_shape = nullptr;
    std::unique_ptr<Shape> selected_shape;
 
    bool isDragged { false };
 
    while (window.isOpen()) {
        sf::Event event;
        while (window.pollEvent(event)){
            if (event.type == sf::Event::Closed){
                selected_shape = nullptr;
                window.close();
            }
 
            if(event.type == sf::Event::MouseButtonPressed){
                for(int i = 0; i < shapes.size(); ++i){
                    if(shapes[i].rect.getGlobalBounds().contains(sf::Mouse::getPosition(window).x, sf::Mouse::getPosition(window).y)){
                        //selected_shape = &shapes[i];
                        selected_shape.reset(&shapes[i]);
                        isDragged = true;
                    }
                }
            }
 
            if(event.type == sf::Event::MouseButtonReleased){
                isDragged = false;
            }
        }
 
        if(isDragged){
            if(selected_shape){
                selected_shape->setPosition(sf::Mouse::getPosition(window).x, sf::Mouse::getPosition(window).y);
            }
        }
 
        window.clear(sf::Color(125, 125, 125, 255));
 
        for(int i = 0; i < shapes.size(); i++){
            window.draw(shapes[i].rect);
        }
 
        window.display();
    }
 
    return 0;
}

J'ai l'impression qu'il ne faut pas utiliser la fonction reset() sur des objets ? 

Par ailleurs, sommes nous d'accord pour dire qu'ici, le pointeur nu ne représente aucun risque, étant donné qu'aucune allocation dynamique n'est effectuée ? 

Merci par avance pour votre aide.

-
Edité par 238 7 avril 2023 à 15:34:50

-----------------------------

Merci pour votre aide.

Juste pour finir, est-ce que ceci pourrait prévenir tout soucis de pointers nuls sur un vector ? :

std::vector<Shape> shapes;
shapes.reserve(64);

en esperant éviter toute réallocation de mémoire, dans la mesure des 64 adresses réservées ? 

Merci.

-
Edité par 238 11 avril 2023 à 19:29:41

  • Partager sur Facebook
  • Partager sur Twitter