2014-04-02 48 views
2

此以下线程程序内的实例:C++不能修改类

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 
     } 
    } 
    [...] 
} 

我打电话成员函数moveSnake(),这是应该修改形成我的蛇的身体细胞的位置。

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 
    [...] 
} 

虽然我的两个坐标我moveSnake内有效地修改()函数,它们不再当我回到我的常规,在那里他们保持初始值。我不明白为什么会发生这种情况,因为如果我尝试在我的moveSnake()函数内修改我的类的任何其他值,则实例会被修改,并且会将此值保留在例程中。

了冲切类:

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

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

蛇:

class Snake 
{ 
public : 

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

最后的细胞:

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; 
}; 

的cell.cpp代码:

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() 
{} 
+1

在我看来,你是在一个多线程环境(或者我没有看到'moveRoutine'使用静态方法的观点)。也许另一个线程在同一时间重新初始化数据。并且要在C++中创建一个线程,如果需要,最好使用'std :: thread'并最终使用'std :: bind',这将保留类结构并防止使用'void *' – Geoffroy

+0

我在这里使用的唯一线程是调用moveRoutine的那个。此外,如果我在moveSnake()中设置了任何其他属性,它将起作用,所以我猜测问题来自于我以这种方式在我的向量中设置Cell的事实,但我看不出为什么。 – Kernael

+0

你可以显示set()和get()的代码吗?我没有看到你的代码不能工作的原因。 @Geoffrey:另一个线程怎么会在那里干扰?除非在Snake中有一个reset()方法或类似的东西。显示的用于设置和获取的测试代码显然是在单个线程中,所以不应该存在缺失写入问题。 –

回答

2

表面上,你的问题(“为什么这个成员不应该被修改,当它应该?”)似乎是合理的。已经显示的设计意图已经足够清晰,我认为它与您所描述的内容相符。但是,你的程序的其他元素已经合谋使它不是这样。

有一件事可能会让你感到困扰的是Undefined Behavior。不管你信不信,即使是最有经验的C++开发者偶尔也会遇到UB。另外,堆栈和堆损坏是导致非常难以隔离的问题的极其简单的方法。你有几件事情要转向以root出来:

调试器(从这里开始!)

  • 用一个简单的单步调试器,您可以通过您的代码行,并在每个检查你的假设转。设置一个断点,执行直到检查内存/变量的状态,再次平分问题空间,迭代。

静态分析

  • 与编译器警告启动和向上移动到皮棉和复杂的商业工具,静态分析可以帮助指出“代码味道”,可能不一定是UB,但可能是死码或者其他地方你的代码可能不会做你认为它的事情。
  • 您是否忽略了您拨打电话的库/操作系统返回的错误?就你而言,你似乎直接操纵内存,但这是期望与现实之间不匹配的常见原因。
  • 您是否有方便的rubber duck

动态分析

  • 工具,比如电子围栏/净化/ Valgrind的(MEMCHECK,helgrind)/地址,消毒,螺纹消毒剂/挡泥板可以帮助查明你写入存储器以外的地区什么被分配。

如果您还没有使用调试器,那么这是您的第一步。如果你以前从未使用过,现在是你必须暂时停顿并学习如何的时候。如果你打算超越这个水平,你会感激你做到了。

如果您在Windows上开发,您很有可能使用Visual Studio。调试器可能很好地集成到您的IDE中。燃烧起来;动起来!

如果您正在linux/BSD/OSX上开发,您可以访问gdbXCode,两者对于此问题都应该足够简单。阅读教程,观看视频,尽其所能,并让调试器滚动。你可能会很快发现你的代码已经修改了一个Snake的实例并打印出另一个实例的内容(或类似的令人沮丧的东西)。

如果在使用调试器时无法重现问题条件,恭喜!您已找到heisenbug。它可能表示一个race condition,仅此信息将帮助您磨练问题的根源。