我正在尝试回答一些过去的纸质问题,这些问题是我在考试中给出的,但对这两个问题并不十分肯定,我们非常感谢任何帮助。 (从图像中键入代码,认为它没问题。)
Q1:识别下面C ++代码中的内存泄漏并解释如何修复它们。 [9分]
#include <string>
class Logger {
public:
static Logger &get_instance () {
static Logger *instance = NULL;
if (!instance){
instance = new Logger();
}
return *instance;
}
void log (std::string const &str){
// ..log string
}
private:
Logger(){
}
Logger(Logger const&) {
}
Logger& operator= (Logger const &) {
}
~Logger() {
}
};
int main(int argcv, char *argv[]){
int *v1 = new int[10];
int *v2 = new int[20];
Logger::get_instance() . log ("Program Started");
// .. do something
delete v1;
delete v2;
return 0;
}
我的回答是,如果main因为提前返回或抛出异常而永远不会执行,则删除将永远不会运行导致永远不会释放内存。 我一直在做一些阅读,我相信auto_ptr会解决问题吗?这会像改变线路一样简单吗? :
auto_ptr<int> v1 = new int[10];
auto_ptr<int> v2 = new int[20];
v1.release();
delete v1;
Q2:为什么虚拟成员需要的内存比没有虚拟成员的类的对象多?
答:因为每个虚拟成员都需要一个指针存储在需要更多空间的vtable中。虽然这相当于空间的增加很少。
答案 0 :(得分:3)
Q1:请注意,v1和v2是分别引用10和20数组的int指针。删除操作符不匹配 - 即,因为它是一个数组,它应该是
delete[] v1;
delete[] v2;
以便释放整个数组。请务必始终匹配new[] and delete[]
和new and delete
我相信你在第二季度已经是正确的了。必须跟踪的vtable和相应的指针会增加内存消耗。
答案 1 :(得分:2)
总结一下:
显示的程序使用不正确的删除形式具有未定义的行为,因此谈论执行的泄漏是无关紧要的
如果前一个被修复,泄漏来自:
修复v1和v2 auto_ptr不是你用new []分配的好广告。你可以使用boost :: auto_array或更好地使v array<int, 10>
或至少vector<int>
。你绝对不要使用release()然后手动删除,而是使用智能指针。
修复实例很有意思。所呈现的内容称为“泄漏单例”,应该泄漏实例。但是在创建之后无处不在,以防某些东西想要在程序退出时使用它。如果不是这样,则不应使用new创建实例,而应直接将其作为本地静态或名称空间静态创建。
这个问题与不相容的东西比较严厉。假设它已被消毒,答案是对于具有虚拟成员实例的类(很可能)携带一个指向VMT的额外指针。此外,VMT本身在一些通用开销之后每个虚拟成员有一个条目。后者确实无关紧要,但前者可能是个问题,因为具有1个字节状态的类可能会拾取8个字节的指针,可能还有7个字节的填充。
答案 2 :(得分:1)
你的第一个答案是正确的,但是审查员可能正在寻找的是释放Logger *instance
在给定的代码中,instance
的内存已分配,但从未取消分配。
第二个答案看起来不错。
答案 3 :(得分:1)
实例永远不会被删除,您需要在main()中使用operator delete []。
答案 4 :(得分:0)
Q1:
很少有人 -我怀疑你的问题是两件事: - 释放单例指针 - 使用delete []
一般来说,过程清理会清理掉悬空的东西..
Q2:
你的第二个问题是正确的,因为虚拟成员需要一个vtable来使类更大