无法解决内存泄漏问题

pue*_*elo 0 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();
Run Code Online (Sandbox Code Playgroud)

因为在"Mountain"类构造函数中:

channel = new ChannelClass(size, size);
Run Code Online (Sandbox Code Playgroud)

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

mount->ShutDown();
delete mount;
mount = 0;
Run Code Online (Sandbox Code Playgroud)

使用Shutdown()定义如下:

if(channel){
    channel->ShutDown();
    delete channel;
    channel = 0;
}
Run Code Online (Sandbox Code Playgroud)

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

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

Use*_*ess 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?
Run Code Online (Sandbox Code Playgroud)

同样,如果山拥有一个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; }
};
Run Code Online (Sandbox Code Playgroud)

现在,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
Run Code Online (Sandbox Code Playgroud)

好的,new毕竟使用

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

另一种情况是,如果您需要运行时多态性,例如,如果您有多个子类,Mountain或者ChannelClass您想要处理基类.

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

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
Run Code Online (Sandbox Code Playgroud)

同样,如果山上的ChannelClass 需要动态地创建,存储一个unique_ptr.

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


哲学

这些C++成语都是基于确定性的破坏,而我们的目标是避免编写明确的清理代码在所有.

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

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