我无法解决我的小程序中的内存泄漏问题.有些代码最初是用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()"可能会导致问题.
如果您需要更多代码,请告诉我们!提前感谢任何愿意提供帮助的人!
好的,所以没有更多的代码,这将非常普遍.这些是最优先的指南(而不是规则).
首先,关于C++ 11的快速说明:如果你没有它,要么替换std::unique_ptr下面的std::auto_ptr(虽然它因为某个原因而被弃用,所以要小心),或者使用boost :: scoped_ptr代替.
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,一切都被自动销毁,并且不需要显式关闭.
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即使函数有多个返回路径,也可以抛出异常等,确保正确释放互斥锁.
如果确实需要编写显式清理代码:不要编写必须调用的自定义关闭方法,只需将其放入析构函数中即可.如果可能的话,也将它推入低级防护对象.