简体   繁体   English

当对象超出范围时是否调用析构函数?

[英]Is a destructor called when an object goes out of scope?

For example:例如:

int main() {
    Foo *leedle = new Foo();

    return 0;
}

class Foo {
private:
    somePointer* bar;

public:
    Foo();
    ~Foo();
};

Foo::~Foo() {
    delete bar;
}

Would the destructor be implicitly called by the compiler or would there be a memory leak?析构函数会被编译器隐式调用还是会出现内存泄漏?

I'm new to dynamic memory, so if this isn't a usable test case, I'm sorry.我是动态内存的新手,所以如果这不是一个可用的测试用例,我很抱歉。

Yes, automatic variables will be destroyed at the end of the enclosing code block.是的,自动变量将在封闭代码块的末尾被销毁。 But keep reading.但继续阅读。

Your question title asks if a destructor will be called when the variable goes out of scope.您的问题标题询问当变量超出范围时是否会调用析构函数。 Presumably what you meant to ask was:想必你想问的是:

will Foo's destructor be called at the end of main()?会在 main() 结束时调用 Foo 的析构函数吗?

Given the code you provided, the answer to that question is no since the Foo object has dynamic storage duration, as we shall see shortly.鉴于您提供的代码,该问题的答案是否定的,因为 Foo 对象具有动态存储持续时间,我们很快就会看到。

Note here what the automatic variable is:请注意这里的自动变量是什么:

Foo* leedle = new Foo();

Here, leedle is the automatic variable that will be destroyed.在这里, leedle是将被销毁的自动变量。 leedle is just a pointer. leedle只是一个指针。 The thing that leedle points to does not have automatic storage duration, and will not be destroyed. leedle指向的东西没有自动保存期限,不会被销毁。 So, if you do this:所以,如果你这样做:

void DoIt()
{
  Foo* leedle = new leedle;
}

You leak the memory allocated by new leedle .您泄漏了new leedle分配的内存。


You must delete anything that has been allocated with new :必须delete已分配的任何内容new

void DoIt()
{
  Foo* leedle = new leedle;
  delete leedle;
}

This is made much simpler and more robust by using smart pointers.通过使用智能指针,这变得更加简单和健壮。 In C++03:在 C++03 中:

void DoIt()
{
  std::auto_ptr <Foo> leedle (new Foo);
}

Or in C++11:或者在 C++11 中:

void DoIt()
{
  std::unique_ptr <Foo> leedle = std::make_unique <Foo> ();
}

Smart pointers are used as automatic variables, as above, and when they go out of scope and are destroyed, they automatically (in the destructor) delete the object being pointed to.智能指针用作自动变量,如上所述,当它们超出范围并被销毁时,它们会自动(在析构函数中) delete所指向的对象。 So in both cases above, there is no memory leak.所以在上述两种情况下,都没有内存泄漏。


Let's try to clear up a bit of language here.让我们试着在这里澄清一些语言。 In C++, variables have a storage duration.在 C++ 中,变量具有存储持续时间。 In C++03, there are 3 storage durations:在 C++03 中,有 3 个存储持续时间:

1: automatic : A variable with automatic storage duration will be destroyed at the end of the enclosing code block. 1:自动: 具有自动存储期的变量将在封闭代码块的末尾被销毁。

Consider:考虑:

void Foo()
{
  bool b = true;
  {
    int n = 42;
  } // LINE 1
  double d = 3.14;
} // LINE 2

In this example, all variables have automatic storage duration.在这个例子中,所有变量都有自动存储持续时间。 Both b and d will be destroyed at LINE 2. n will be destroyed at LINE 1. bd都将在第 2 行销毁。 n将在第 1 行销毁。

2: static : A variable with static storage duration will be allocated before the program begins, and destroyed when the program ends. 2: static :一个具有静态存储期的变量会在程序开始前分配,在程序结束时销毁。

3: dynamic : A variable with dynamic storage duration will be allocated when you allocate it using dynamic memory allocation functions (eg, new ) and will be destroyed when you destroy it using dynamic memory allocation functions (eg, delete ). 3: dynamic :具有动态存储期的变量在使用动态内存分配函数(例如new )分配时将被分配,当您使用动态内存分配函数(例如delete )销毁它时将被销毁。

In my original example above:在我上面的原始示例中:

void DoIt()
{
  Foo* leedle = new leedle;
}

leedle is a variable with automatic storage duration and will be destroyed at the end brace. leedle是一个具有自动存储持续时间的变量,将在大括号结束时销毁。 The thing that leedle points to has dynamic storage duration and is not destroyed in the code above. leedle指向的东西是动态存储时长的,在上面的代码中并没有被销毁。 You must call delete to deallocate it.您必须调用delete来释放它。

C++11 also adds a fourth storage duration: C++11 还增加了第四个存储持续时间:

4: thread : Variables with thread storage duration are allocated when the thread begins and deallocated when the thread ends. 4:线程:具有线程存储期的变量在线程开始时分配,在线程结束时释放。

Yes, if an object goes out of scope, the destructor gets called.是的,如果对象超出范围,则会调用析构函数。 BUT No, the destructor won't be called in this case, because you only have a pointer in scope, that pointer has no particular destructor, so there will be no indirect call to Foo 's destructor.但是不,在这种情况下不会调用析构函数,因为您在范围内只有一个指针,该指针没有特定的析构函数,因此不会间接调用Foo的析构函数。

This example is the application domain of smart pointers like std::unique_ptr and std::shared_ptr .这个例子是像std::unique_ptrstd::shared_ptr这样的智能指针的应用领域。 Those are actual classes that, unlike raw pointers have a destructor, (conditionally) calling delete on the pointed-to object.这些是实际的类,与原始指针不同,它们具有析构函数,(有条件地)对指向的对象调用delete

Btw, Foo 's destructor deletes bar , bur bar has never been initialized nor assigned to an address that points to an actual object, so the delete call will give undefined behavior, likely a crash.顺便说一句, Foo的析构函数删除bar , bur bar从未被初始化或分配给指向实际对象的地址,因此删除调用将给出未定义的行为,可能会导致崩溃。

there would be a memory leak indeed.确实会有内存泄漏。 The destructor for the object which goes out of scope (the Foo*) gets called, but the one for the pointed-to object (the Foo you allocated) does not.超出范围的对象(Foo*)的析构函数被调用,但指向对象(您分配的 Foo)的析构函数没有被调用。

Technically speaking, since you are in the main, it is not a memory leak, since you up to when the application is not terminated you can access every allocated variable.从技术上讲,由于您在 main 中,因此它不是内存泄漏,因为在应用程序未终止之前,您可以访问每个分配的变量。 With this respect, I cite Alexandrescu (from Modern C++, the chapter about singletons)在这方面,我引用了 Alexandrescu(来自现代 C++,关于单例的章节)

Memory leaks appear when you allocate accumulating data and lose all references to it.当您分配累积数据并丢失对它的所有引用时,就会出现内存泄漏。 This is not the case here: Nothing is accumulating, and we hold knowledge about the allocated memory until the end of the application.这不是这里的情况:没有任何东西在累积,我们掌握有关已分配内存的知识,直到应用程序结束。 Furthermore, all modern此外,所有现代

Of course, this does not imply that you should not call delete , as it would be an extremely bad (and dangerous) practice.当然,这并不意味着您不应该调用delete ,因为这将是一种非常糟糕(且危险)的做法。

First note that the code wouldn't compile;首先要注意代码不会编译; new returns a pointer to an object allocated on the heap. new返回一个指向在堆上分配的对象的指针。 You need:你需要:

int main() {
    Foo *leedle = new Foo();
    return 0;
}

Now, since new allocates the object with dynamic storage instead of automatic, it's not going out of scope at the end of the function.现在,由于new使用动态存储而不是自动分配对象,因此它不会在函数结束时超出范围。 Therefore it's not going to get deleted either, and you have leaked memory.因此它也不会被删除,并且您已经泄漏了内存。

In this instance, when main returns it's the end of the program, the Operating system will handle freeing all resources.在这种情况下,当 main 返回时,程序结束,操作系统将处理释放所有资源。 If, for instance this was any other function, you would have to use delete.例如,如果这是任何其他函数,则必须使用 delete。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 对象超出范围之前调用的析构函数 - Destructor Called Before Object Goes Out Of Scope 局部变量的析构函数是否始终保证在超出范围时被调用? - Is the destructor of the local variable always guaranteed to be called when it goes out of scope? 为什么当对象超出范围时我们说析构函数调用? - Why We Say Destructor Call When Object Goes out of Scope? 当这些对象中的任何一个没有超出范围时,为什么要调用析构函数? - Why destructor is called when any of these object not going out of scope? 在多线程处理过程中,对象析构函数始终被调用,但对象并未超出范围 - Object destructor kept being called when multithreading, yet the object is not out of scope 在临时之前调用的析构函数应该超出范围 - destructor called before temporary should be out of scope 当指针在 cpp 17 中超出引用时是否调用非默认析构函数? - Does the non default destructor be called when a pointer goes out of reference in cpp 17? 当对象超出范围时执行一些代码 - Execute some code when an object goes out of scope 在对象超出范围/无效时得到通知 - Get notified when object goes out of scope/gets invalid 在 switch case 中对象超出范围时的访问冲突 - Access violation when the object goes out of scope in switch case
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM