当 class 的指针实例超出范围时,不调用析构函数是真的吗?
Is it true that destructors aren't called when a pointer instance of a class goes out of scope?
以这段代码为例:
class MyClass
{
public:
~MyClass()
{
cout << "Destructor called\n";
}
};
int main()
{
MyClass Testvar;
// destructer called for this
MyClass *ptrvar;
ptrvar = &Testvar;
// but not for this
}
给我带来了很多困惑。上面的代码打印:
调用的析构函数
只有一次。我在 main 中声明了两个 MyClass 实例,其中一个是 MyClass 类型的普通变量,另一个是指向普通变量的相同类型的指针。这里不需要析构函数(没有动态分配),但为了举例,我在 class 中定义了一个。所以,因为定义了两个 class 实例,所以析构函数应该被调用两次。但是当我 运行 这段代码时,这并没有发生。如果我删除指针并再定义一个普通实例,程序将打印:
调用了析构函数
调用的析构函数
我的观察是,当指针实例超出范围时,不会隐式调用析构函数。我是对的还是只是遗漏了什么。
I declared two MyClass instances inside main
不,你没有。您声明了 MyClass
的实例并创建了指向该实例的指针。就这些了。
您的代码行为是正确的。
My observation is that destructors are not implicitly called when a pointer instance goes out of scope. Am I right or just missing something.
没错。 C++ 不提供这样做的 garbage collector. You have to keep track of your pointers by yourself. You can use the smart pointers。
您只创建了一个对象,并且只为该对象调用了析构函数。
指针不实例化另一个对象,它只是指向前一个
当分配在堆栈上的对象超出范围时以及当动态创建的对象(使用 operator new)被显式销毁(operator delete)时调用析构函数
您实际上只实例化了一个 MyClass
类型的对象。这行发生了:
MyClass Testvar;
在下一行中,您只声明了一个指向 MyClass
类型对象的指针,但这并没有创建一个新对象:
MyClass *ptrvar;
并且在这一行中,您将第一个 MyClass
的地址分配给您的指针:
ptrvar = &Testvar;
所以指针指向的是同一个对象,你仍然只有一个 MyClass
的实例。当作用域关闭时,TestVar
被删除,您会看到析构函数被调用一次。
您可以创建一个新的 MyClass
对象(在堆上)并将其地址分配给您的指针,如下所示:
MyClass *ptrvar = new MyClass();
现在您确实有两个 MyClass
对象。但是,当范围关闭时,您仍然只会看到一个对象被删除。这是因为 new
在堆上而不是在堆栈上创建对象,并且此类对象不会在创建它们的作用域结束时自动删除。您必须使用 delete
:
手动执行此操作
delete ptrvar;
执行此行时,您会看到调用了析构函数。如果你不这样做,你就把你的对象留在了堆上,并且有 "leaked" 它占用的内存。
为了避免手动执行所有这些操作,您应该使用 C++ 提供的内置智能指针。
以这段代码为例:
class MyClass
{
public:
~MyClass()
{
cout << "Destructor called\n";
}
};
int main()
{
MyClass Testvar;
// destructer called for this
MyClass *ptrvar;
ptrvar = &Testvar;
// but not for this
}
给我带来了很多困惑。上面的代码打印: 调用的析构函数 只有一次。我在 main 中声明了两个 MyClass 实例,其中一个是 MyClass 类型的普通变量,另一个是指向普通变量的相同类型的指针。这里不需要析构函数(没有动态分配),但为了举例,我在 class 中定义了一个。所以,因为定义了两个 class 实例,所以析构函数应该被调用两次。但是当我 运行 这段代码时,这并没有发生。如果我删除指针并再定义一个普通实例,程序将打印:
调用了析构函数 调用的析构函数
我的观察是,当指针实例超出范围时,不会隐式调用析构函数。我是对的还是只是遗漏了什么。
I declared two MyClass instances inside main
不,你没有。您声明了 MyClass
的实例并创建了指向该实例的指针。就这些了。
您的代码行为是正确的。
My observation is that destructors are not implicitly called when a pointer instance goes out of scope. Am I right or just missing something.
没错。 C++ 不提供这样做的 garbage collector. You have to keep track of your pointers by yourself. You can use the smart pointers。
您只创建了一个对象,并且只为该对象调用了析构函数。
指针不实例化另一个对象,它只是指向前一个
当分配在堆栈上的对象超出范围时以及当动态创建的对象(使用 operator new)被显式销毁(operator delete)时调用析构函数
您实际上只实例化了一个 MyClass
类型的对象。这行发生了:
MyClass Testvar;
在下一行中,您只声明了一个指向 MyClass
类型对象的指针,但这并没有创建一个新对象:
MyClass *ptrvar;
并且在这一行中,您将第一个 MyClass
的地址分配给您的指针:
ptrvar = &Testvar;
所以指针指向的是同一个对象,你仍然只有一个 MyClass
的实例。当作用域关闭时,TestVar
被删除,您会看到析构函数被调用一次。
您可以创建一个新的 MyClass
对象(在堆上)并将其地址分配给您的指针,如下所示:
MyClass *ptrvar = new MyClass();
现在您确实有两个 MyClass
对象。但是,当范围关闭时,您仍然只会看到一个对象被删除。这是因为 new
在堆上而不是在堆栈上创建对象,并且此类对象不会在创建它们的作用域结束时自动删除。您必须使用 delete
:
delete ptrvar;
执行此行时,您会看到调用了析构函数。如果你不这样做,你就把你的对象留在了堆上,并且有 "leaked" 它占用的内存。
为了避免手动执行所有这些操作,您应该使用 C++ 提供的内置智能指针。