2

我正在尝试回答一些过去的考试练习题,但对这两个问题不太确定,非常感谢任何帮助。(从图像上输入代码,认为没关系)。

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

4

5 回答 5

3

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

delete[] v1;
delete[] v2;

这样整个数组就被释放了。记住要始终匹配new[] and delete[]new and delete

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

于 2013-06-04T21:49:47.047 回答
2

简单总结一下:

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

  2. 如果先前已修复,则泄漏将来自:

    • 新的记录器();// 总是
    • 其他两个新用途,如果随后的新抛出或字符串 ctor 抛出或日志中的 ... 部分抛出。
  3. 修复 v1 和 v2 auto_ptr 不是用 new[] 分配的好广告。您可以使用 boost::auto_array 或更好地制作 varray<int, 10>或至少vector<int>. 而且您绝对不要使用 release() 然后手动删除,而是将其引导到智能指针。

  4. 修复实例很有趣。所呈现的称为“泄漏单例”,它应该泄漏实例。但是在创建后无所不在,以防在程序退出期间想要使用它。如果这不是故意的,则不应使用 new 创建实例,而是直接使用本地静态或命名空间静态创建实例。

  5. 比较不相容的事物时,这个问题的措辞很糟糕。假设它已被清理,答案是具有虚拟成员实例的类(很可能)携带一个指向 VMT 的额外指针。此外,经过一些一般开销后,VMT 本身每个虚拟成员都有一个条目。后者确实无关紧要,但前者可能是个问题,因为具有 1 字节状态的类可能会获取 8 字节指针,并且可能还有另外 7 字节的填充。

于 2013-06-05T00:28:46.550 回答
1

您的第一个答案是正确的以获得学分,但考官可能正在寻找的是释放Logger *instance

在给定的代码中,instance分配了内存,但从未解除分配。

第二个答案看起来不错。

于 2013-06-04T21:49:37.980 回答
1

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

于 2013-06-04T21:50:16.407 回答
0

Q1:

几个gotchyas -

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

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

然而,一般来说,过程清理会清理悬空的东西。

Q2:

你的第二个问题是对的,因为虚拟成员需要一个 vtable,这使得类更大

于 2013-06-04T21:54:23.410 回答