See this code:
COleDateTime CSpecialEventDlg::GetSpecialEventDate() noexcept
{
COleDateTime datEvent;
if (datEvent.SetDateTime(m_datEvent.GetYear(),
m_datEvent.GetMonth(),
m_datEvent.GetDay(),
0, 0, 0) != 0)
{
// Error
}
return datEvent;
}
My code analysis said I could add noexcept
(which I did). But I decided to investigate a little more. I noticed that SetDateTime
returns a value:
Zero
if the value of thisCOleDateTime
object was set successfully; otherwise,1
. This return value is based on theDateTimeStatus
enumerated type. For more information, see theSetStatus
member function.
For that latter function (SetStatus
) it states:
The status parameter value is defined by the
DateTimeStatus
enumerated type, which is defined within the COleDateTime class. SeeCOleDateTime::GetStatus
for details.
Now, the documentation for GetStatus
is documented to have a definition of:
DateTimeStatus GetStatus() const throw();
So, it throws an exception if there is an error. Therefore, I decided to look at the MFC source for SetDateTime
:
inline int COleDateTime::SetDateTime(
_In_ int nYear,
_In_ int nMonth,
_In_ int nDay,
_In_ int nHour,
_In_ int nMin,
_In_ int nSec) throw()
{
SYSTEMTIME st;
::ZeroMemory(&st, sizeof(SYSTEMTIME));
st.wYear = WORD(nYear);
st.wMonth = WORD(nMonth);
st.wDay = WORD(nDay);
st.wHour = WORD(nHour);
st.wMinute = WORD(nMin);
st.wSecond = WORD(nSec);
m_status = ConvertSystemTimeToVariantTime(st) ? valid : invalid;
return m_status;
}
It uses ConvertSystemTimeToVariantTime
to set the status. That uses:
inline BOOL COleDateTime::ConvertSystemTimeToVariantTime(_In_ const SYSTEMTIME& systimeSrc)
{
return AtlConvertSystemTimeToVariantTime(systimeSrc,&m_dt);
}
And that uses:
inline BOOL AtlConvertSystemTimeToVariantTime(
_In_ const SYSTEMTIME& systimeSrc,
_Out_ double* pVarDtTm)
{
ATLENSURE(pVarDtTm!=NULL);
//Convert using ::SystemTimeToVariantTime and store the result in pVarDtTm then
//convert variant time back to system time and compare to original system time.
BOOL ok = ::SystemTimeToVariantTime(const_cast<SYSTEMTIME*>(&systimeSrc), pVarDtTm);
SYSTEMTIME sysTime;
::ZeroMemory(&sysTime, sizeof(SYSTEMTIME));
ok = ok && ::VariantTimeToSystemTime(*pVarDtTm, &sysTime);
ok = ok && (systimeSrc.wYear == sysTime.wYear &&
systimeSrc.wMonth == sysTime.wMonth &&
systimeSrc.wDay == sysTime.wDay &&
systimeSrc.wHour == sysTime.wHour &&
systimeSrc.wMinute == sysTime.wMinute &&
systimeSrc.wSecond == sysTime.wSecond);
return ok;
}
At this point I have got lost. In short, I am assuming that SetDateTime
does not throw an exception.
I understand this much, if I decide to make a call to GetStatus
inside the if
clause then we do have a potential for exception to be thrown.
All three MFC functions for which you have shown the source code (
COleDateTime::SetDateTime
,COleDateTime::ConvertSystemTimeToVariantTime
andAtlConvertSystemTimeToVariantTime
) have – according to their declarations – the potential to throw exceptions (because they have no specification to the contrary, such asnoexcept
).However, that doesn't mean that they will (or are even likely to). Digging a bit further into the MFC source code, the only place I can see, in those three functions, where an exception could be thrown is in the
ATLENSURE(pVarDtTm!=NULL);
line (in the third function).The
ATLENSURE
macro is defined as follows:And
ATLENSURE_THROW
is, in turn, defined thus:So, it would seem that, in your code, an exception will be thrown if
expr
(in the above snippets) is null (the double-bang,!!
pseudo-operator makes any non-zero value into1
and leaves a zero as zero). Thatexpr
is the result of thepVarDtTm!=NULL
expression, which can only be0
(false
) if the&m_dt
argument in the call in your second MFC source excerpt is itself NULL – and, as the address of a member of the class object through which it is being called, that seems improbable (if not impossible).Another issue you have is that you appear to misunderstand what the
throw()
specification in theDateTimeStatus GetStatus() const throw();
declaration means. As described here, it is actually (since C++17) an alias fornoexcept
(ornoexcept(true)
, to be more precise). To specify that a function can throw any type of exception, thethrow(...)
ornoexcept(false)
specifications should be used (or use no except/throw specification at all).So, your last sentence is not really true:
Because the
GetStatus()
function is specified explicitly as non-throwing, and you already have a call to theSetDateTime
member function, which (as described above) can throw an exception (but won't, in your code).