Like already suggested in comments, the trivial solution is to put the commands in a script instead of in a function. The script runs in a subprocess with its own environment, and doesn't change anything in the parent. When the child finishes, nothing from its environment is left.
If you need to use a function, Bash has a local keyword which makes the variable's scope local to the current function. When the function ends, all variables are reset to their state from before the function ran (unset if they were unset, previous value if they were set).
If you want to set variables and have them set outside of a function, but have a simple way to revert them to their original value, you really have to build that yourself. Look at how Python's virtualenv does it, for example (a common and popular example, though not necessarily the absolutely most robust) -- it basically writes out the previous values to the definition of the deactivate command which disables the virtual environment and (attempts to) return things to the way they were before you ran activate.
# bash 4+ only!
setVariables () {
declare -A _setvariables_old=([A]="$A" [B]="$B" [C]="$C")
A="~/"
B=$(du -sh /smth)
C="tralala"
}
setVariables
:
cleanup () {
local var
for var in "${!_setvariables_old[@]}"; do
printf -v "$var" "%s" "${_setvariables_old[$var]}"
done
unset _setvariables_old
}
This leaks slightly (what if _setvariables_old is a variable you want to preserve!?) and doesn't know how to unset things; it just reverts to an empty string if something was unset before you started.
local. They will then drop out of scope (destroyed) at the end of the function.