C ++:在方法中创建对象并在方法之外使用它

时间:2014-11-10 08:14:08

标签: c++

代码很简单:

class SuperClass
{
public:
    virtual void someMethod() = 0;
};

class SubClass : public SuperClass
{
public:
    virtual void someMethod()
    {
        std::cout << "hello" << std::endl;
    }
};

class CallerClass
{
public:
    std::vector<SuperClass*> subClasses;

    CallerClass()
    {
        subClasses.push_back(&SubClass());
    }

    void callMethods()
    {
        subClasses[0]->someMethod();
    }
};

int main(int argx, char**argv)
{
    CallerClass cc;
    cc.callMethods();

    return 0;
}

当我实际调用tryler在CallerClass的'callMethods()'中调用subClass''someMethod()'时,会出现问题。在Visual Studio中,它只是在该行代码中断而没有任何解释。我通过将push_back(&amp; SubClass())更改为push_back(new SubClass())来解决了这个问题。

我很好奇为什么后者有效而不是前者。我认为这是因为在方法中创建的对象只存在于方法中,并且通过使用“new”,实际上在函数结束后为该对象分配了空间;但我在SuperClass中添加了一个int a = 1,并且能够以类似于'callMethods()'内部的方式访问它。

我必须在这里忽略C ++的一些基本方面。请通知我。希望这不是太明显的事情。

2 个答案:

答案 0 :(得分:1)

subClasses.push_back(&SubClass());

您正在存储一个临时对象的指针,该对象在之后被销毁。

然后,当你调用someMethod时,你正在一个已经删除的无效对象指针上调用一个方法。

subClasses.push_back(new SubClass());

您正在存储指向有效对象的指针,因此它可以正常工作。

答案 1 :(得分:1)

是的,如果你push_back(&SubClass()),你正在添加一个指向临时对象的向量的指针。在表达式结束时,将删除临时对象。当您调用callMethods时,您将取消引用指向已删除对象的指针。这是未定义的行为,任何事情都可能发生,它甚至可以工作!

通过调用push_back(new SubClass());,您将在堆上分配一个对象,并将该对象的指针添加到向量中。表达式结束时,不会删除堆上的此对象。

实际上,此对象根本不会被删除,并且会导致程序中出现内存泄漏。 CallerClass有效地拥有了这些对象,因此它有责任在完成后删除它们。

要修复内存泄漏,您需要进行一些更改。您需要向SuperClass添加公共虚拟析构函数:

virtual ~SuperClass(){};

这确保了如果您在SuperClass上调用析构函数,SubClass也将被正确销毁。然后,您需要确保在delete析构函数中调用CallerClass。您可以通过显式编写析构函数,循环遍历向量的元素并调用delete来做到这一点,但更简单的C ++ 11方法是使用像std::unique_ptr这样的智能指针。如果您将矢量更改为:

std::vector<std::unique_ptr<SuperClass>> subClasses;

然后,对象将在CallerClass析构函数中自动删除,您根本不必显式编写析构函数。

Live Demo