我无法在我的小程序中解决内存泄漏问题。有些代码最初是用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()”可能会导致问题。
如果您需要更多代码,请告诉我们!提前感谢任何愿意提供帮助的人!
答案 0 :(得分:6)
好的,所以如果没有更多的代码,这将非常普遍。这些是最优先的指南(而不是规则)。
首先,关于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?
同样地,如果一个山拥有一个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
完全一样长,所有内容都会自动销毁,并且不需要显式关闭。
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
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
同样,如果要动态创建山峰的ChannelClass
,请将 存储在unique_ptr
中。
在您需要复制对象以传递它们时,有时也可能会有所帮助,复制非常昂贵,并且您不能依赖(或者还没有)RVO或移动语义。这是一个优化,所以不要担心它,除非分析显示它是一个问题。
这些C ++习语都基于确定性破坏,目标是避免在所有中编写显式清理代码。
将内存管理委派给容器(如std::vector
)和智能指针(如std::unique_ptr
)可以避免Java使用垃圾回收进行内存泄漏。但是,它强有力地推广到RAII,其中类似的自动范围的保护对象可以自动管理所有资源,而不仅仅是内存。例如,std::lock_guard
确保正确释放互斥锁,即使函数有多个返回路径,也可能抛出异常等等。
如果你做需要编写显式清理代码:不要编写你必须调用的自定义关闭方法,只需将它放在析构函数中。如果可能的话,也将它推入低级防护对象。