There are already many useful answers, but I will try to add a little, maybe this will help someone.
First of all, as others have already noted, dereferencing a nullptr or an invalid pointer (address) does not throw an exception in standard C ++. MSVC supports it through Structured Exception Management , but it is not portable. Read more about this at.
The try block function in the constructor does not allow you to throw an exception, it will be propagated in any case, if you have not chosen another. And when you enter the catch clause, all members of the class are already destroyed. So the only plausible thing you can do about this is to log an error or somehow modify some global variables. That is why he considered it more or less useless.
Regarding your source code
Test2(Test* pTest):m_pTest(pTest), m_nDuplicateID(pTest->getTestID()) { }
you can use the ternary operator to check the zero value of pTest only in the list of initializers and perform some appropriate actions if it is equal to zero; just set m_nDuplicateID to nullptr or some other value depending on its type, call another function and use its return type, etc.:
Test2(Test* pTest): m_pTest(pTest), m_nDuplicateID( pTest ? pTest->getTestID() : ) { }
you could use several nested ternary operators to create more complex execution threads.
And just for completeness, this is not the case with your code, but it can carry someone in the same situation. If you used a member of your class m_pTest to initialize m_nDuplicateID, this will depend on the order of these members in the class declaration, since class members in the list of initializers are initialized in the order of declaration, and not in the order in which they appear in the list of initializers, so this can be a problem, and it's better to avoid dependencies on member initialization order:
class A { A( B* pTest ); int m_nDuplicateID; B* m_pTest; }; A::A( B* pTest ) : m_pTest( pTest ), m_nDuplicateID( m_pTest->someMethod() )