请参阅以下代码:
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;
}我的代码分析说我可以添加noexcept (我确实添加了)。但我决定再调查一下。我注意到SetDateTime返回一个值:
如果成功设置了此
Zero对象的值,则为COleDateTime;否则为1。此返回值基于DateTimeStatus枚举类型。有关更多信息,请参见SetStatus成员函数。
对于后一个函数(SetStatus),它声明:
状态参数值由
DateTimeStatus枚举类型定义,该枚举类型是在COleDateTime类中定义的。详情请参见COleDateTime::GetStatus。
现在,GetStatus的文档被记录为具有以下的定义:
DateTimeStatus GetStatus()康斯特抛出()
因此,如果有错误,它将抛出异常。因此,我决定查看SetDateTime的MFC源代码。
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;
}它使用ConvertSystemTimeToVariantTime设置状态。它使用:
inline BOOL COleDateTime::ConvertSystemTimeToVariantTime(_In_ const SYSTEMTIME& systimeSrc)
{
return AtlConvertSystemTimeToVariantTime(systimeSrc,&m_dt);
}这就使用了:
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;
}在这一点上我迷路了。简而言之,我假设SetDateTime 没有抛出异常。
我非常理解这一点,如果我决定在GetStatus子句中调用if,那么我们确实有可能引发异常。
发布于 2021-10-16 21:03:01
您已经展示了源代码(COleDateTime::SetDateTime、COleDateTime::ConvertSystemTimeToVariantTime和AtlConvertSystemTimeToVariantTime)的所有三个MFC函数都有--根据它们的声明--有可能抛出异常(因为它们没有相反的规范,比如noexcept)。
然而,这并不意味着他们会(甚至有可能)。深入研究MFC源代码,在这三个函数中,我能看到的唯一地方是在ATLENSURE(pVarDtTm!=NULL);行(在第三个函数中)中可以抛出异常。
ATLENSURE宏的定义如下:
#define ATLENSURE(expr) ATLENSURE_THROW(expr, E_FAIL)而ATLENSURE_THROW则是这样定义的:
#define ATLENSURE_THROW(expr, hr) \
do { \
int __atl_condVal=!!(expr); \
ATLASSUME(__atl_condVal); \
if(!(__atl_condVal)) AtlThrow(hr); \
} __pragma(warning(suppress:4127)) while (0)因此,在您的代码中,如果expr (在上述代码段中)为null (双邦、!!伪运算符将任何非零值放入1并将零保留为零),则会引发异常。该expr是pVarDtTm!=NULL表达式的结果,该表达式只能是0 (false),如果第二个MFC源摘录中的调用中的&m_dt参数本身为空,并且作为调用该类对象的类对象的一个成员的地址,这似乎不可能(如果不是不可能的话)。
另一个问题是,您似乎误解了throw()声明中的DateTimeStatus GetStatus() const throw();规范的含义。作为在此描述,它实际上(自C++17)是noexcept (或者更准确地说是noexcept(true) )的别名。要指定一个函数可以抛出任何类型的异常,应该使用throw(...)或noexcept(false)规范(或者根本不使用任何以外/抛出规范)。
所以,你的最后一句话并不是真的:
我非常理解这一点,如果我决定在
GetStatus子句中调用if,那么我们确实有可能引发异常。
因为GetStatus()函数被显式地指定为非抛出,而且您已经调用了SetDateTime成员函数,这个函数(如上所述)可以抛出异常(但在代码中不会抛出)。
https://stackoverflow.com/questions/69598644
复制相似问题