-3
class Entity {
    //attributes
public:
    float X, Y;
    Entity() {
        X = 0;
        Y = 0;
        cout << "Created Entity!" << endl;
    }
    ~Entity() {
        cout << "Entity Destroyed!" << endl;
    }
    void Print() {
        cout << X << ", " << Y << endl;
}




};
void func() {
    Entity e;
    e.Print();
    
}
int main()
{
    func();
    cout << "b";
}

So I'm kinda having trouble understanding what exactly is happening here, I don't understand when and how e is out of scope. func creates e and then calls the method function but all that only gets executed when I call func in main right? So only when I call func in main e gets created and the method gets called but how exactly is it ever out of scope?

Like can someone please try to explain this like I'm a 5 year old? The entity only gets created when func gets called in main right? When could e ever be out of scope?

  • 3
    Too lazy to write a decent answer, but, in a nutshell: when the scope (which, essentially, is the space between `{`, and `}`), in which `e` was created in, ends. In this case, upon return from `func` function. – Algirdas Preidžius Aug 10 '21 at 17:27
  • 5
    This is a (functionally) exact duplicate of the previous question you posted here https://stackoverflow.com/questions/68729466/destructor-what-is-happening-here. Look at the answer here:https://stackoverflow.com/questions/6403055/object-destruction-in-c – Lala5th Aug 10 '21 at 17:30
  • 2
    It does seem like the same question is being rephrased here. "Variable scope" has both been explained here, as well as in early chapters of any introductory book. Perhaps @juicyxda could [edit] this question to explain why [the duplicate](https://stackoverflow.com/questions/6403055/object-destruction-in-c) was unclear or unsatisfactory? – Drew Dormann Aug 10 '21 at 17:31
  • 1
    But what I said is true right? The object 'e' only gets created when I call func in main right? Likeee technically e was "created" in func but it doesn't really exist until I call func in main right? –  Aug 10 '21 at 17:35
  • 1
    You're mixing up scope and control flow. Yes, `e` is not created until `func` is called, but that doesn't tell you when its scope _ends_ (or at least, not more clearly than the dupe of your other question) – Useless Aug 10 '21 at 17:37

3 Answers3

2

I don't understand when and how e is out of scope

The scope of e is everything from its declaration to the end of its enclosing block scope:

void func()
{                 // start of block scope
    Entity e;     // e created in the enclosing block scope here
    e.Print();    
}                 // end of block scope, e (and any other automatic locals) destroyed

but all that only gets executed when I call func in main right?

Now you're mixing up two things:

  1. scope is the section of the source code where e is a valid identifier (and refers to the same object, in case you have other variables with the same name in other code). This is static, it's all known at compile time.
  2. control flow is what when func is actually executed, enters its block scope, executes the statements in the function body, and finally exits block scope (destroying any automatic local objects at the same time). This happens at runtime, and is dynamic (in the sense that it might depend on conditional logic, or input).

So only when I call func in main e gets created and the method gets called but how exactly is it ever out of scope?

It has automatic scope, so its scope ends when the enclosing block does. For e, that's when func has finished executing and before control returns to main.

... When could e ever be out of scope?

Try referring to e in main after the call to func. Does it compile?

No, because e isn't an identifier in this scope.

What's the alternative? Every large program would accumulate every variable name that was ever used in the global namespace. It would rapidly become unmanageable, and in fact that's exactly the reason we use local variables instead of globals.


Note that we can disentangle scope from lifetime just by returning something. If we choose something with dynamic lifetime:

std::unique_ptr<Entity> foo()
{                                           // block begins
  std::unique_ptr<Entity> e;                // e scope begins
  e.reset( new Entity );                    // *e lifetime begins
  e->Print();
  return std::move(e);                      // *e moves to return value
}                                           // e destroyed

int main()
{
  auto f = foo();                           // *e is now called *f
  f->Print();
}                                           // f destroyed and deletes *f
  1. You can see there's an anonymous object (created by new), which is pointed at first by *e and then by *f
  2. e has the same (block) scope as before
  3. e has the same (automatic) lifetime, so it is destroyed when it goes out of scope
  4. the object originally known as *e is handed off to f, and keeps existing. It still doesn't have an identifier of its own that could be bound to a scope.
  5. f also has block scope & automatic lifetime
  6. *f (the dynamic object formerly known as *e) is destroyed along with f only because we didn't move it elsewhere.
Useless
  • 64,155
  • 6
  • 88
  • 132
  • Yeah this was a good answer thanks but it's not like I'm ever using the object e after calling func right? I just call the function and then after that it's not like I'm ever using an object thats out of scope right? So is it basically just that after this func finishes e just kinda self destructs? –  Aug 10 '21 at 17:51
  • Like I said, the object called `e` stops existing (and yes, its destructor is called if it has one). But more than that, you _can't_ refer to it outside of `func` because the name isn't visible outside its block scope. That's why I invited you to try it: the compiler will tell you it has no idea what you're talking about. – Useless Aug 10 '21 at 18:00
  • Right but I'm not referring to it am I? I just don't really understand how people are saying e is out of scope because like idk (I know they're right) but it's not like I'm ever doing anything with e after calling func() so I'm not touching an object that's out of scope at ALL. So idk just kinda hard for me to understand how e is destroyed because it's out of scope like in my brain rn I'm just like "I call func in main, func creates that object does whatever code with it, then that func in which the entity was created finishes and e just gets destroyed" is that right? –  Aug 10 '21 at 18:04
  • Yes. I feel like I've confirmed that like three times now. The end of scope is the `}` ... that's the point at which you can no longer refer to `e` by name. The end of lifetime is the same place because there's no use keeping `e` around after you can't refer to it any more. You can just stick a breakpoint in `~Entity` in your debugger to confirm exactly where it gets called. – Useless Aug 10 '21 at 18:11
1

e is created once you called func and will be destroyed when that function finishes its execution. So its scope is only within that function braces.

ShahzadIftikhar
  • 515
  • 2
  • 11
0

From your comments I think you're having a little trouble with what scope means in this context. It is true that e is created after a call to func in main. However, in C++ one thing the {} symbols denote scope. Here e is declared within the scope of func(inside the brackets of the function) meaning the scope of e is locale to the function. This means that once func returns that variable will go out of scope and thus the destructor is called since it is not longer accessible. This scoping is also why you cannot use e outside of func even though the function is called from main.

BTables
  • 4,413
  • 2
  • 11
  • 30