识别内存泄漏

时间:2013-06-04 21:42:40

标签: c++ memory memory-leaks

我正在尝试回答一些过去的纸质问题,这些问题是我在考试中给出的,但对这两个问题并不十分肯定,我们非常感谢任何帮助。 (从图像中键入代码,认为它没问题。)

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中。虽然这相当于空间的增加很少。

5 个答案:

答案 0 :(得分:3)

Q1:请注意,v1和v2是分别引用10和20数组的int指针。删除操作符不匹配 - 即,因为它是一个数组,它应该是

delete[] v1;
delete[] v2;

以便释放整个数组。请务必始终匹配new[] and delete[]new and delete

我相信你在第二季度已经是正确的了。必须跟踪的vtable和相应的指针会增加内存消耗。

答案 1 :(得分:2)

总结一下:

  1. 显示的程序使用不正确的删除形式具有未定义的行为,因此谈论执行的泄漏是无关紧要的

  2. 如果前一个被修复,泄漏来自:

    • new Logger(); //总是
    • 另外两个新用途,如果后续的新投掷或字符串ctor抛出或日志中的...部分抛出。
  3. 修复v1和v2 auto_ptr不是你用new []分配的好广告。你可以使用boost :: auto_array或更好地使v array<int, 10>或至少vector<int>。你绝对不要使用release()然后手动删除,而是使用智能指针。

  4. 修复实例很有意思。所呈现的内容称为“泄漏单例”,应该泄漏实例。但是在创建之后无处不在,以防某些东西想要在程序退出时使用它。如果不是这样,则不应使用new创建实例,而应直接将其作为本地静态或名称空间静态创建。

  5. 这个问题与不相容的东西比较严厉。假设它已被消毒,答案是对于具有虚拟成员实例的类(很可能)携带一个指向VMT的额外指针。此外,VMT本身在一些通用开销之后每个虚拟成员有一个条目。后者确实无关紧要,但前者可能是个问题,因为具有1个字节状态的类可能会拾取8个字节的指针,可能还有7个字节的填充。

答案 2 :(得分:1)

你的第一个答案是正确的,但是审查员可能正在寻找的是释放Logger *instance

在给定的代码中,instance的内存已分配,但从未取消分配。

第二个答案看起来不错。

答案 3 :(得分:1)

实例永远不会被删除,您需要在main()中使用operator delete []。

答案 4 :(得分:0)

Q1:

很少有人 -

  • 单例模式是非常危险的,例如它不是线程安全的,两个线程可以进入并创建两个类 - 导致内存泄漏,使用EnterCriticalSection或其他一些线程同步机制进行环绕,并且仍然不安全且不建议使用
  • 单身类不释放他们的记忆,单身人士应该被重新计算才能真正行动。
  • 你在函数内部使用静态变量,甚至比使用类的静态成员更糟糕。
    • 您使用new []分配并删除而不使用delete []

我怀疑你的问题是两件事: - 释放单例指针 - 使用delete []

一般来说,过程清理会清理掉悬空的东西..

Q2:

你的第二个问题是正确的,因为虚拟成员需要一个vtable来使类更大