代码很简单:
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 ++的一些基本方面。请通知我。希望这不是太明显的事情。
答案 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
析构函数中自动删除,您根本不必显式编写析构函数。