Which variables to define in ofApp.h?

I wonder which variables to define in ofApp.h.
Is it the best practice to define all used variables in ofApp.h or does it make sense to define some variables that are only locally used in ofApp.cpp (like int i in a for loop, for example)?

Hi, ofApp is a class so you should define there the variables that you want to live as long as the class does. In the case of ofApp, almost always that will be all the time that the app is running. Also you should define there the variables that you might want to access from the differnt functions.

1 Like

@roymacdonald thanks.

Hey Jona, I like to think about scope, which roymacdonald alluded to. Objects in c++ get destroyed once they go out of scope; I generally try to define variables within the (smallest) scope that applies to them.

So, an object that gets used in different functions within ofApp is defined as a class member of ofApp, because its scope would encompass all of ofApp.

But, if I just need a temporary object as part of a function, say something like an ofPixels object to store an ofTexture before saving it to a .jpg file, then I’ll usually define it inside the .saveToFile() function that uses it. Thus the scope of the ofPixels object is local to that function, and then its perfectly fine when it gets destroyed once it “goes out of scope” because the function is the only place where it is used.

The same is true for variables in a loop. If their scope is limited to the loop, I define them inside the loop. I don’t need them outside the loop and so I want them to go out of scope. Letting variables “go out of scope”, and understanding when and why they do, is an important part of c++.

I also avoid creating objects every cycle that are big or require a chunk of resources to create and/or allocate. So for instance I would never use an ofFbo inside of ofApp::update() that was local, because allocating it every cycle would take a lot of resources. I would instead make it a member of ofApp, allocate it once in ofApp::setup(), and then use it (each cycle) inside of ofApp::update(). An ofFbo would be a member of ofApp, even though the only place it might be used is in ofApp::update().

2 Likes

@TimChi thanks, that helped a lot. Is that also the reason, why one should deallocate “bigger” variables that are defined in ofApp.h, with, for example, ofVideoPlayer().close() or ofImage.clear(), manually when exiting the app?

Hey you know I’m not completely sure about the deallocation. It certainly can’t hurt. And I think with c++ it may depend if the objects are created on the heap vs the stack.

I tend to only create objects on the stack, and I don’t deallocate them, even the big ones. I trust that with c++, when an object goes out of scope, even with the termination of ofApp, that the destructors will destroy (all) objects and free the memory associated with them when they no longer exist. I’ve noticed that the memory usage in the system monitor will sometimes increase when an app runs, and then decrease again when it terminates. So I feel OK that the memory associated with the app is freed when ofApp exits.

The heap is different. The memory associated with objects that involve smart pointers have some memory management that is helpful. C-style pointers require more management, and the memory must be freed with the delete keyword. Failure to properly delete pointers and objects on the heap results in a memory leak, as the allocated but inactive (and inaccessible) memory accumulates over time.

I’ve noticed in other c/c++ stuff I’ve looked at (like the Vulkan tutorial for example) that objects are explicitly freed when a program terminates. But this might be because these APIs are really c and not c++, and require more explicit management of memory. I don’t know c very well, but maybe this is one of the big differences between c++ and c. C++ has (default) constructors and destructors associated with every object, whereas this is not the case with c.

1 Like

@TimChi thanks for you thorough explanation. I was a bit lazy to do that myself :grimacing:

I never do that, as the destruction of the ofApp object should handle such. I would worry only if I get an error at exit, otherwise C++ will handle it. More over, most modern OSes will free the memory of an app, even if it was leaking, after it has exited.

1 Like

One question, that is somehow related: Is it better to clear / resize / reserve and reuse a std::map or a std::vector than to initialize a new one every time (inside of a scope)?

I found this: c++ - clearing a vector or defining a new vector, which one is faster - Stack Overflow
c++ - What's the fastest way to reinitialize a vector? - Stack Overflow
c++ - How to clear a vector but keeping its capacity? - Stack Overflow

Edit: If I understand it right, clear() is the best way (if the size of the vector is unknown)? From my third link:

cppreference said explicitly that the capacity of the vector is unchanged.

from cppreference:

void clear();

Removes all elements from the container. Invalidates any references, pointers, or iterators referring to contained elements. May invalidate any past-the-end iterators.
Leaves the capacity() of the vector unchanged.

I like to use std::vector::reserve() if the vector is potentially going to hold a lot of elements. Vectors are a contiguous block of memory. If they get too large for their present location, they get copied to a new location with more memory. This is fine if they’re small, but gets more resource intensive as they get larger. std::map is not contiguous, so it can reside in many different locations in memory.

I also like to reuse vectors if possible. You can clear them if you like, before resizing them. And then I usually like to resize them before looping thru them, as opposed to calling .push_back() in a loop.

For me, the choice of scope (class vs local) for any container would probably reflect the scope of the values it contains. So, I’d use a vector with local scope if it only contained local values. Also there may be some gray areas. I’ve read that compilers will (often) optimize with std::move() in the following case:

// classVector is a member of a class
std::vector<float> classVector;

void updateClassVector(){
    std::vector<float> localVector(50, 1.f);
    // std::move() applied here? instead of a copy?
    classVector = localVector;
}

Also, you can always get the size of a vector by calling .size().

1 Like