0

I see at catch exception by pointer in C++ , it is said to throw an exception by value and catch it by reference.

Therefore, I write the following codes:

class CMyException : public CException
{
};

void CTestExceptionDlg::OnBnClickedButton1()
{
    // TODO: Add your control notification handler code here
    throw CMyException();
}

However, this will cause compiler error:

1>TestExceptionDlg.cpp
1>d:\program files (x86)\microsoft visual studio 9.0\vc\atlmfc\include\afx.h(763) : error C2248: 'CObject::CObject' : cannot access private member declared in class 'CObject'
1>        d:\program files (x86)\microsoft visual studio 9.0\vc\atlmfc\include\afx.h(561) : see declaration of 'CObject::CObject'
1>        d:\program files (x86)\microsoft visual studio 9.0\vc\atlmfc\include\afx.h(532) : see declaration of 'CObject'
1>        This diagnostic occurred in the compiler generated function 'CException::CException(const CException &)'

However, if I modify the codes to throw a newed exception, like this:

class CMyException : public CException
{
};

void CTestExceptionDlg::OnBnClickedButton1()
{
    // TODO: Add your control notification handler code here
    throw new CMyException();
}

Then the error will disappear.

Why? This seems against the policy that one should throw exception by value and not allocate it from heap?

Update:

Below is the declaration of CException:

class AFX_NOVTABLE CException : public CObject
{
    // abstract class for dynamic type checking
    DECLARE_DYNAMIC(CException)

public:
// Constructors
    CException();   // sets m_bAutoDelete = TRUE
    explicit CException(BOOL bAutoDelete);   // sets m_bAutoDelete = bAutoDelete

// Operations
    void Delete();  // use to delete exception in 'catch' block

    virtual BOOL GetErrorMessage(_Out_z_cap_(nMaxError) LPTSTR lpszError, _In_ UINT nMaxError,
        _Out_opt_ PUINT pnHelpContext = NULL) const ;
    virtual BOOL GetErrorMessage(_Out_z_cap_(nMaxError) LPTSTR lpszError, _In_ UINT nMaxError,
        _Out_opt_ PUINT pnHelpContext = NULL);
    virtual int ReportError(UINT nType = MB_OK, UINT nMessageID = 0);

// Implementation (setting m_bAutoDelete to FALSE is advanced)
public:
    virtual ~CException() = 0;
    BOOL m_bAutoDelete;
#ifdef _DEBUG
    void PASCAL operator delete(void* pbData);
#if _MSC_VER >= 1200
    void PASCAL operator delete(void* pbData, LPCSTR lpszFileName, int nLine);
#endif
protected:
    BOOL m_bReadyForDelete;
#endif
};

Below is the declaration of CObject:

class AFX_NOVTABLE CObject
{
public:

// Object model (types, destruction, allocation)
    virtual CRuntimeClass* GetRuntimeClass() const;
    virtual ~CObject() = 0;  // virtual destructors are necessary

    // Diagnostic allocations
    void* PASCAL operator new(size_t nSize);
    void* PASCAL operator new(size_t, void* p);
    void PASCAL operator delete(void* p);
#if _MSC_VER >= 1200
    void PASCAL operator delete(void* p, void* pPlace);
#endif

#if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)
    // for file name/line number tracking using DEBUG_NEW
    void* PASCAL operator new(size_t nSize, LPCSTR lpszFileName, int nLine);
#if _MSC_VER >= 1200
    void PASCAL operator delete(void *p, LPCSTR lpszFileName, int nLine);
#endif
#endif

    // Disable the copy constructor and assignment by default so you will get
    //   compiler errors instead of unexpected behaviour if you pass objects
    //   by value or assign objects.
protected:
    CObject();
private:
    CObject(const CObject& objectSrc);              // no implementation
    void operator=(const CObject& objectSrc);       // no implementation

// Attributes
public:
    BOOL IsSerializable() const;
    BOOL IsKindOf(const CRuntimeClass* pClass) const;

// Overridables
    virtual void Serialize(CArchive& ar);

#if defined(_DEBUG) || defined(_AFXDLL)
    // Diagnostic Support
    virtual void AssertValid() const;
    virtual void Dump(CDumpContext& dc) const;
#endif

// Implementation
public:
    static const CRuntimeClass classCObject;
#ifdef _AFXDLL
    static CRuntimeClass* PASCAL _GetBaseClass();
    static CRuntimeClass* PASCAL GetThisClass();
#endif
};
alancc
  • 487
  • 2
  • 24
  • 68
  • Can you show the deceleration of `CObject`. It seems that compiler cannot copy `CObject` in copy constructor of `CException`. – MRB Dec 16 '19 at 07:16
  • @MRB, I have included the declaration of CObject and CException. Thank you. – alancc Dec 16 '19 at 08:48

1 Answers1

1

The standard requires that an object being thrown (if of class type) must have an accessible copy/move constructor, see this question.

So this CException class and anything derived from it cannot be thrown. If you can modify it then stop deriving from CObject (which is non-copyable). Or if it is a part of system headers then it is not suitable for this purpose; you could use the std::exception hierarchy instead.

M.M
  • 138,810
  • 21
  • 208
  • 365