Gut, der Debug-Mode, der - wie der Name verrät - nur zum Debuggen geeignet ist, fügt Bounds Checking usw. hinzu. Das ändert jedoch nichts daran, dass die Standard-Iteratoren oftmals/immer(?) keine Exceptions werfen. Der Grund dafür ist einfach: Um die STL schlank und möglichst schnell zu halten, wurden Iteratoren so konzipiert, dass jeder Pointer ein gültiger Iterator ist. Und wer schon öfters mal Typ-Fehler mit Templates hatte, konnte gelegentlich sehen, dass viele Iteratoren, vor allem von std::vector, auch tatsächlich als simple Pointer umgesetzt wurden.
Und Pointer werfen nunmal keine Exceptions. Sie geben dir höchstens SIGSEGV oder Access Violation. Wie BlueCobold schrieb, ist es hier sinnvoll, Assertions einzusetzen. Wahlweise auch welche, die im Release-Modus noch drin sind. Das Programm stürzt dann zwar auch ab, wenn ein Fehler passiert, aber wenigstens kannste dich dabei mit vielen Informationen anreichern, die dir ein "normaler" Crash nicht liefert. Etwa Datei und Zeilennummer.
Assertions sind eigentlich fast immer gut, aber sie ersetzen keines Wegs besser durchdachten Code. Wenn du dir nicht sicher bist, ob dein Iterator eines, z.B., std::vectors später mal noch gültig ist, wenn du ihn brauchst, dann sind Iteratoren nicht das Werkzeug, mit dem du arbeiten sollst. Iteratoren sind dazu da, sofort verwendet zu werden. Nutze statt dessen Indices oder Keys. Wenn du z.B. immer das siebte Element krallen willst, greifste dir später einfach my_vector[7]. Und wenn du dir nichtmals sicher bist, ob der Index noch innerhalb des Wertebereichs des std::vectors liegt, dann nutze eben my_vector.at(7), das eine Exception wirft, sobald der Index Murks ist.