1

请参阅此代码:

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),它声明:

status参数值由DateTimeStatus枚举类型定义,该类型在COleDateTime中定义。详情请参阅COleDateTime::GetStatus

现在,文档GetStatus被记录为具有以下定义:

DateTimeStatus GetStatus() const throw();

因此,如果出现错误,它会引发异常。因此,我决定查看 MFC 源代码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;
}

它用于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那么我们确实有可能引发异常。

4

1 回答 1

1

COleDateTime::SetDateTime根据它们的声明,您已经展示了源代码的所有三个 MFC 函数(COleDateTime::ConvertSystemTimeToVariantTimeAtlConvertSystemTimeToVariantTime)都有可能引发异常(因为它们没有相反的规范,例如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就是表达式的结果,如果第二个 MFC 源代码摘录中的调用中的参数本身pVarDtTm!=NULL为 NULL,则表达式的结果只能是0( false) ——并且,作为调用它的类对象成员的地址,即似乎不太可能(如果不是不可能的话)。&m_dt


您遇到的另一个问题是您似乎误解了声明中的throw()规范的DateTimeStatus GetStatus() const throw();含义。如此处所述,它实际上(自 C++17 起)是noexcept(或者noexcept(true),更准确地说)的别名。要指定函数可以抛出任何类型的异常,应使用throw(...)or规范(或根本不使用异常/抛出规范)。noexcept(false)

所以,你的最后一句话不是真的:

我明白这一点,如果我决定GetStatus在子句内部进行调用,if那么我们确实有可能引发异常。

因为该GetStatus()函数被明确指定为非抛出,并且您已经调用了SetDateTime成员函数,(如上所述)可以抛出异常(但不会在您的代码中)。

于 2021-10-16T21:03:01.000 回答