2009-12-16 17 views
1

注意:这不是家庭作业IT与提供给我们按我们的教授模拟考试来帮助我们准备我们的考试写作,检查在C内存泄漏++测试用例

我目前正在研究编程考试。在他们给我们的样本测试之一中,我们有以下问题:

假设您已获得一个模板化容器,该容器包含无序的对象集合。

template <typename T> 
class Container { 
    public: 
     void insert(T *op); 
     // EFFECTS: inserts the object pointed to by op into 
     // the container 
     T *remove(); 
     // EFFECTS: removes an object from the Container, and 
     // returns a pointer to it. Returns NULL if no 
     // objects remain in the Container. 
     // Note: the implementation can choose which 
     // object to return if more than one exists. 
     Container(); // ctor 
     Container(const Container &l); // copy ctor 
     Container &operator=(const Container &l); // assignment 
     ~Container(); // dtor 
    private: 
     ... 
}; 

请注意,这只是接口;为简洁起见,省略了实施细节。然而,你可能会认为实现是基于节点的;链接的节点集合 保存对象。

您怀疑析构函数的实现不满足最不变式的保守规则,而是正在泄漏内存。写一个验收测试(类似于项目4)来检查这种情况。您必须提供合适的包含类型和执行测试的主体。

请注意,您不能依赖任何语言未定义的行为,您可能不需要 假定您有来自Project 5的altnew分配器可供您使用,并且您可能不会 覆盖delete操作符。提示:您可以使用全局变量。

不过,我觉得是这样的:

#include <iostream> 

using namespace std; 

int *p = NULL; 

void leak() { 
    int *num = new int(5); 
    p = num; 
    delete num; 
} 

int main() { 
    if ((*p = 6)) { 
     cout << "Memory leak\n"; 
    } else { 
     cout << "No Leak\n"; 
    } 
} 

这背后的基本思想是我,虽然我写不出来,我还没有分配的内存空间。在编译这个测试代码时,虽然它的工作很好,但显然你可以。有关如何编写这样的测试用例的想法?

+0

自己所想的测试依赖于不确定的行为。当您访问free'd内存时会发生什么情况未定义。 – 2009-12-16 20:16:07

+0

我想你可以用'Container <使用全局变量计算它本身的实例>'进行测试。 – UncleBens 2009-12-16 20:22:09

+0

你可能想解释Project 5中的“altnew”分配器是什么。也许这为您提供了跟踪分配的工具。 – 2009-12-16 20:34:20

回答

4

如果您创建一个类用作模板参数,该参数将在其构造函数中将1添加到全局变量中,并在其析构函数中将该全局变量减1,该怎么办?

然后,你可以在容器上执行任何你想要的测试(创建它,填充它,清空它,删除它等),并通过在容器被销毁后检查全局变量为0来检查内存泄漏。

5

当你说:

void leak() { 
    int *num = new int(5); 
    p = num; 
    delete num; 
} 

没有内存泄漏。然而,如果解除引用,悬挂指针(p)会导致未定义的行为。

+0

对。你看,我认为当你使用删除命令时,它会释放,你将不能再写入该内存地址。我测试了我的程序,编译时使用了和不使用delete num程序,但是在两种情况下都表示没有内存泄漏。对于实际的考试,我不得不使用给予我们的方法,但这段代码只是为了测试显然无效的概念。 – blcArmadillo 2009-12-16 20:24:08

+0

删除num程序=删除num行 – blcArmadillo 2009-12-16 20:24:58

+0

一旦删除,如果你写入内存你有什么C++调用“未定义的行为” - 任何事情都可能发生。你的代码甚至可能似乎工作。但没有泄漏。 – 2009-12-16 20:29:51

0

我不确定项目4和项目5中列出的是什么,但我认为这样做的方法是为插入到容器中的对象分配一个全局指针(按提示)。如果你然后销毁容器,它应该销毁其中的对象,并且该全局指针现在应该为空。

+1

不会。全局指针不会受到删除容器的影响,它只会是悬挂的,如果取消引用则会失败 - 这可能是需要的。实施留给学生练习。 :-) – 2009-12-16 20:27:00

+0

这就是我的意思 - 测试它是否失败。如果它没有失败,那么它是泄漏的。 – aronchick 2009-12-18 21:01:31

0

您可以在T构造函数中递增一个整型全局变量,并在T析构函数中递减它:这样做会告诉您T实例是否被容器销毁。验收测试可以将一些T实例分配到一个Container实例中,销毁该Container,并测试是否销毁了T实例(即是否调用了T析构函数)。

没有重写delete运算符我没有看到一个简单的方法来告诉是否容器不仅破坏牛逼的实例,但也释放出的T实例占用内存:但如果破坏牛逼实例(其中你可以按照上面的第一段所述进行测试),那么你可能会希望它的可能是也释放每个实例占用的内存。

0

我会使用一个包含引用计数的类型。在容器中插入物品时,引用计数应该增加。当你销毁容器时,它应该递减到它的初始值。引用计数可以保存在全局变量(如建议)或类中的静态变量(我通常使用后者,但稍微复杂一些)。

+0

感谢您的信息。你的意思是在插入和解构方法的实现中添加该代码吗?如果是这样,我不认为我可以做到这一点,因为我没有编写方法实现。 – blcArmadillo 2009-12-16 20:50:06

+0

否 - 这将全部存储在被存储的对象中。正常情况下,它在该课程中完成'ctors和dtor - 每个ctor增加计数,并且dtor减少计数。另一种可能性是让ctors和dtors在打印字符串时说出它们的运行时间。 – 2009-12-16 21:01:11

4

你可以使用一个元素类像这样的,这也将它的实例:

class InstCounter { 
public: 
    static int counter; 
    InstCounter() { counter++; } 
    ~InstCounter() { counter--; } 
}; 
int InstCounter::counter = 0; 

int main(int argc, char** argv) 
{ 
    { Container<InstCounter> c; 
    // insert elements... 
    c.insert(new InstCounter); 
    } // calls dtor of c 
    if (InstCounter::counter > 0) 
    std::cout << "Container is leaking." << std::endl; 
    return 0; 
} 
+0

这与我的想法是一致的。但是,使用静态成员变量可能比我对全局变量的建议更优雅。加Wolfgang实际上写出了代码:)所以使用这个! – 2009-12-17 03:02:39