2010-01-21 52 views
2

我已经开始编写一个简单的控制台Yahtzee游戏进行练习。我只是有一个关于这个函数是否会泄漏内存的问题。每次需要重新滚动骰子时都会调用滚动函数。C++会这个函数泄漏吗?

它所做的是创建一个动态数组。第一次使用它会存储5个随机值。对于下一次运行,除了您想要保留的骰子外,它只会重新展开。我有另一个功能,但因为它是不相关的这个问题,我离开了出来

主要功能

int *kast = NULL;   //rolled dice 
int *keep_dice = NULL; //which dice to re-roll or keep 

kast = roll(kast, keep_dice); 
delete[] kast; 

与这里的功能

int *roll(int *dice, int *keep) { 

    srand((unsigned)time(0)); 
    int *arr = new int[DICE]; 
    if(!dice) 
    { 
     for(int i=0;i<DICE;i++) 
     { 

      arr[i] = (rand()%6)+1; 
      cout << arr[i] << " "; 
     } 
    } 
    else 
    { 
     for(int i=0;i<DICE;i++) 
     { 
      if(!keep[i]) 
      { 
       dice[i] = (rand()%6)+1; 
       cout << "Change "; 
      } 
      else 
      { 
       keep[i] = 0; 
       cout << "Keep "; 
      } 
     } 
     cout << endl; 
     delete[] arr; 
     arr = NULL; 
     arr = dice; 

    } 
    return arr; 
} 
+4

有人告诉过你在删除它们后总是给NULL指定NULL吗?他们错了。 – 2010-01-21 15:27:47

+0

'arr = NULL; arr =骰子;'相当多余。 :]如果即使只进行了第一级优化,该行也不会存在于编译后的输出中。 ('arr = NULL;') – GManNickG 2010-01-21 15:35:47

+0

@Steve:我记得在书中读到它。是什么让它错了?我认为这只是出于安全原因。 – jasonline 2010-01-21 15:35:57

回答

12

是的,它可以泄漏。举例来说,使用cout可能会引发异常,如果是,则不会调用delete

而不是自己分配一个动态数组,您可能需要考虑返回一个std::vector。更好的是,把你的函数变成一个适当的算法,它需要一个迭代器(在这种情况下,一个back_insert_iterator)并在那里写输出。

编辑:仔细看看它,我觉得有必要指出我完全不喜欢这段代码的基本结构。你有一个功能是真正做两种不同的事情。你也有一对你并行寻址的数组。我将它重构成两个独立的函数,一个roll和一个re_roll。我重组数据作为结构的数组:

struct die_roll { 
    int value; 
    bool keep; 

    die_roll() : value(0), keep(true) {} 
}; 

执行初始辊,传递一个矢量(或阵列,如果你真的坚持)的这些给roll功能,其填充在初始值。要进行重新滚动,您将向量传递到re-roll,该滚动重新滚动以获得任何die_roll的新值,其keep成员已设置为false

+0

或者,使用'auto_ptr'是有益的。 – 2010-01-21 15:26:11

+0

Sry没有提到那些cout只用于错误检查。无论如何,除了这是防泄漏的功能和阵列删除正确? – starcorn 2010-01-21 15:29:57

+1

@klw:是的,只要你确保在分配和释放内存之间不会抛出异常,你的代码应该没有内存泄漏。但是,这种情况意味着您的代码(无双关语意思)充其量是非常脆弱的。 – 2010-01-21 15:37:09

4

使用(重新建立了新分配)std::vector而不是数组,并将其引用传递给该函数。这样,你就可以确定它不会泄漏。

+0

我已经考虑使用矢量,但由于我已经知道我想要多大的列表,我认为使用数组会更好。 – starcorn 2010-01-21 15:30:41

+0

@klw:什么?这没有意义。一个'std :: vector'是你的代码的标准和安全版本,知道大小没有意义,只需在vector上调用'resize'或'reserve'即可。 – GManNickG 2010-01-21 15:38:11

+0

确实;如果你使用正确的构造函数,那么不需要重新分配,你不会为这些支付费用。它可能和数组一样快,而且更容易一些。 – Thomas 2010-01-21 15:41:42

4

分配内存的方式很混乱:在函数内部分配的内存必须由函数外部的代码释放。

为什么不重写它是这样的:

int *kast = new int[DICE];   //rolled dice 
bool *keep_dice = new bool[DICE]; //which dice to re-roll or keep 
for (int i = 0; i < DICE; ++i) 
    keep_dice[i] = false; 

roll(kast, keep_dice); 

delete[] kast; 
delete[] keep_dice; 

这符合你的new S和delete很好s上行。至于功能:因为我们设置keep_dice所有false,参数都不为过NULL,它总是修改dice,而不是返回一个新数组,它简化为:

void roll(int *dice, int *keep) { 
    for(int i=0;i<DICE;i++) 
    { 
     if(keep[i]) 
     { 
      keep[i] = false; 
      cout << "Keep "; 
     } 
     else 
     { 
      dice[i] = (rand()%6)+1; 
      cout << "Change "; 
     } 
    } 
    cout << endl; 
} 

此外,你应该移动srand通话到你程序的开始。重播对于随机性非常不利。

+0

感谢您的输入 – starcorn 2010-01-21 15:41:52

0

我的建议是花时间购买/借阅并阅读Scott Meyers Effective C++ 3rd Edition。为了成为富有成效的C++程序员,你将会节省数月的痛苦。我从个人痛苦的经历中发言。

+0

感谢您的建议 – starcorn 2010-01-21 21:36:12