Question

Inside this following thread routine :

void*   Nibbler::moveRoutine(void* attr)
{
  [...]
      Nibbler*  game = static_cast<Nibbler*>(attr);

      while (game->_continue == true)
       {
         std::cout << game->_snake->_body.front()->getX() << std::endl; // display 0
         std::cout << game->getDirection() << std::endl; // display 0
         game->moveSnake();
         std::cout << game->_snake->_body.front()->getX() << std::endl; // display 0
         std::cout << game->getDirection() << std::endl; // display 42
       }
    }
  [...]
}

I am calling the member function moveSnake(), which is supposed to modify the positions of the cells forming my snake's body.

void    Nibbler::moveSnake()
{
  [...]
  std::cout << this->_snake->_body.front()->getX() << std::endl; // display 0
  this->_snake->_body.front()->setX(3);
  this->_direction = 42;
  std::cout << this->_snake->_body.front()->getX() << std::endl; // display 3
  [...]
}

Although my two coordinates are effectively modified inside my moveSnake() function, they are not anymore when I go back to my routine, where they keep their initial value. I don't understand why this is happening, since if I try to modify any other value of my class inside my moveSnake() function, the instance is modified and it will keep this value back in the routine.

The Nibbler class :

class Nibbler
{
public :
  [...]
  void          moveSnake();
  static void*  moveRoutine(void*);

private :
  [...]
  int           _direction
  Snake*        _snake;
  IGraphLib*    _lib;
  pthread_t     _moveThread;
...
};

The snake :

class   Snake
{
public :

  [...]
  std::vector<Cell*>    _body;
};

And finally the cell :

class   Cell
{
public :

  void  setX(const int&);
  void  setY(const int&);

  int   getX() const;
  int   getY() const;

  Cell(const int&, const int&);
  ~Cell();

private :

  int   _x;
  int   _y;
};

The cell.cpp code :

void        Cell::setX(const int& x)
{
  this->_x = x;
}

void        Cell::setY(const int& y)
{
  this->_y = y;
}

int     Cell::getX() const
{
  return this->_x;
}

int     Cell::getY() const
{
  return this->_y;
}

Cell::Cell(const int& x, const int& y)
{
  this->_x = x;
  this->_y = y;
}

Cell::~Cell()
{}
Était-ce utile?

La solution

On its face, your question ("why does this member not get modified when it should?") seems reasonable. The design intent of what has been shown is clear enough and I think it matches what you have described. However, other elements of your program have conspired to make it not so.

One thing that may plague you is Undefined Behavior. Believe it or not, even the most experienced C++ developers run afoul of UB occasionally. Also, stack and heap corruption are extremely easy ways to cause terribly difficult-to-isolate problems. You have several things to turn to in order to root it out:

Debuggers (START HERE!)

  • with a simple single-step debugger, you can walk through your code and check your assumptions at every turn. Set a breakpoint, execute until, check the state of memory/variables, bisect the problem space again, iterate.

Static analysis

  • Starting with compiler warnings and moving up to lint and sophisticated commercial tools, static analysis can help point out "code smell" that may not necessarily be UB, but could be dead code or other places where your code likely doesn't do what you think it does.
  • Have you ignored the errors returned by the library/OS you're making calls into? In your case, it seems as if you're manipulating the memory directly, but this is a frequent source of mismatch between expectations and reality.
  • Do you have a rubber duck handy?

Dynamic analysis

  • Tools like Electric Fence/Purify/Valgrind(memcheck, helgrind)/Address-Sanitizer, Thread-Sanitizer/mudflaps can help identify areas where you've written to memory outside of what's been allocated.

If you haven't used a debugger yet, that's your first step. If you've never used one before, now is the time when you must take a brief timeout and learn how. If you plan on making it beyond this level, you will be thankful that you did.

If you're developing on Windows, there's a good chance you're using Visual Studio. The debugger is likely well-integrated into your IDE. Fire it up!

If you are developing on linux/BSD/OSX, you either have access to gdb or XCode, both of which should be simple enough for this problem. Read a tutorial, watch a video, do whatever it takes and get that debugger rolling. You may quickly discover that your code has been modifying one instance of Snake and printing out the contents of another (or something similarly frustrating).

If you can't duplicate the problem condition when you use a debugger, CONGRATULATIONS! You have found a heisenbug. It likely indicates a race condition, and that information alone will help you hone in on the source of the problem.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top