What issue with the destructors is this causing? (Despite now knowing where the problem lies I'm still not sure how I can fix it)
The same way you find and fix invalid pointers elsewhere.
Usually the easiest is to catch it in a debugger or to generate a crash dump and review it.
With it open in the debugger, look at the call stack at the time of the crash. Something told the program to look at that location. Since it is after main() returned, it is possibly a destructor or some code called by a destructor or possibly code registered to be run by atexit() or some other method.
Often in the debugger you can discover the exact line number of the function that dereferenced the memory, other times you just get the function names. Occasionally you will just get a memory region that requires looking it up in the executable's map file. Rarely you will have corrupted your stack or other memory to the point where you cannot identify the location, and then you have a nightmare debugging scenario far beyond the scope of a forum post. If know the exact instruction within a line, identifying the pointer is done for you, it is the pointer listed in the instruction. If you know the line, look for all the potential pointers that could be followed. If it is a full function, look for all the potential pointers in the function as well as any calls that are made within the function.
Usually the process is very quick. Most often it is just an object that has been destroyed but either wasn't zeroed out after destruction, or a dangling reference to something. Occasionally it is a different problem, like an overwritten memory buffer.
Anyway, once you find it, eliminate it. If the pointer was previously zeroed out, just add a null check and verify the solution. If the pointer wasn't zeroed out, search the code for all the places that can potentially release that piece of memory and make sure they zero it out after release, and still add the null check; then verify the solution.
EDIT: Since you helpfully provided some info from your call stack, the isspace() and the open() suggest it is something dealing with a file stream cleanup. Pick those functions in the debugger, see what they are and what they contain. The open() function looks like it is very near your main function, so it should provide a convenient place to backtrack from.