无法解决内存泄漏问题

时间:2012-08-21 17:45:02

标签: c++ memory-leaks

我无法在我的小程序中解决内存泄漏问题。有些代码最初是用Java创建的,所以我把它“转换”成c ++(其中一些东西可能看起来很奇怪,所以如果你有更好的解决方案,请告诉我 - 对于C ++中的OOP来说还是很新的)。 我的目的是创建一个随机高度图生成器。 有2个内存泄漏(在Visual Leak Detector中找到):

第一个在这里被触发:

-> Mountain* mount = new Mountain(size, Utils::powerOf2Log2(size) - 6, 0.5f, seed);
   ChannelClass* height = mount->toChannel();

因为这个在“Mountain”类构造函数中:

channel = new ChannelClass(size, size);

我试图像这样使用关机方法:

mount->ShutDown();
delete mount;
mount = 0;

使用Shutdown()定义如下:

if(channel){
    channel->ShutDown();
    delete channel;
    channel = 0;
}

“ChannelClass”的ShutDown()方法正在删除一个float数组。我最初的想法是,“ChannelClass * height = mount-> toChannel()”可能会导致问题。

如果您需要更多代码,请告诉我们!提前感谢任何愿意提供帮助的人!

1 个答案:

答案 0 :(得分:6)

好的,所以如果没有更多的代码,这将非常普遍。这些是最优先的指南(而不是规则)。

首先,关于C ++ 11的快速说明:如果你没有它,请用std::unique_ptr替换下面的std::auto_ptr(虽然它因某种原因而被弃用,所以要小心),或者改为使用boost::scoped_ptr

1。不要使用new

如果你需要创建一个(单个)山和需要在声明它的范围之外保持活着,只需将它用作具有自动范围的常规变量:

void automatic_scope(int size, double seed)
{
    Mountain hill(size, Utils::powerOf2Log2(size) - 6, 0.5f, seed);
    // ... mountainous operations happen here ...
}   // hill is destroyed here - is that ok for you?

同样地,如果一个山拥有一个ChannelClass,只要拥有它的山就应该 ,只需这样做:

class Mountain
{
    ChannelClass channel;

public:
    Mountain(int size, int powerthing, double something, double seed)
    : channel(size, size) // initialize other members here
    {
        // any more initialization
    }

    ChannelClass& toChannel() { return channel; }
};

现在ChannelClass将与Mountain完全一样长,所有内容都会自动销毁,并且不需要显式关闭。

2。不要使用new[]

同样,如果您需要几个范围有限的山脉,请使用

void automatic_scope_vector(int size, double seed)
{
    std::vector<Mountain> hills;
    hills.push_back(Mountain(size, Utils::powerOf2Log2(size) - 6, 0.5f, seed));
    // ... mountainous operations happen here ...
}   // hills are all destroyed here

3。好的,毕竟使用new

显然使用new的正当理由:已经提到了一个(你需要让你的山脉比你创建它们的块更长)。

另一种情况是,如果您需要运行时多态性,例如,如果您有多个MountainChannelClass的子类,但您想要处理基类。

我们可以用多态工厂函数来说明:

class Molehill: public Mountain { ... };
class Volcano: public Mountain { ... };

std::unique_ptr<Mountain> make_mountain(int size, double seed, bool is_molehill)
{
    std::unique_ptr<Mountain> result;
    if (is_molehill)
        result.reset(new Molehill(size, size/2, 0.01f, seed));
    else
        result.reset(new Volcano(size, size*2, 0.5f, seed));
    return result;
}

void automatic_scope_polymorphic(int size, double seed, bool is_molehill)
{
    std::unique_ptr<Mountain> hill = make_mountain(size, seed, is_molehill);
    // ... polymorphic mountainous operations happen here ...
}   // hill is destroyed here unless we gave the unique_ptr to someone else

同样,如果要动态创建山峰的ChannelClass ,请将 存储在unique_ptr中。

在您需要复制对象以传递它们时,有时也可能会有所帮助,复制非常昂贵,并且您不能依赖(或者还没有)RVO或移动语义。这是一个优化,所以不要担心它,除非分析显示它是一个问题。


哲学

这些C ++习语都基于确定性破坏,目标是避免在所有中编写显式清理代码

将内存管理委派给容器(如std::vector)和智能指针(如std::unique_ptr)可以避免Java使用垃圾回收进行内存泄漏。但是,它强有力地推广到RAII,其中类似的自动范围的保护对象可以自动管理所有资源,而不仅仅是内存。例如,std::lock_guard确保正确释放互斥锁,即使函数有多个返回路径,也可能抛出异常等等。

如果你需要编写显式清理代码:不要编写你必须调用的自定义关闭方法,只需将它放在析构函数中。如果可能的话,也将它推入低级防护对象。