CERT.OOP.PTR_MEMBER.NO_MEMBER

Do not use pointer-to-member operators to access nonexistent members.

Do not use pointer-to-member operators to access nonexistent members, include null pointer to member value.

Vulnerability and risk

Abbreviating pm-expression.*cast-expression as E1.*E2, E1 is called the object expression. If the dynamic type of E1 does not contain the member to which E2 refers, or if the second operand is the null pointer to member value, the behavior is undefined.

Mitigation and prevention

Do not use a pointer-to-member expression where the dynamic type of the first operand does not contain the member to which the second operand refers, including the use of a null pointer-to-member value as the second operand.

Example

Copy
  struct B1 {
    virtual ~B1() = default;
  };
  
  struct D1 : B1 {
    virtual ~D1() = default;
    virtual void g() { /* ... */ }
  };
  
 void f1() {
   B1 *b = new B1;
 
   // ...
 
   void (B1::*gptr)() = static_cast<void(B1::*)()>(&D1::g);      //Non compliant
   (b->*gptr)();
   delete b;
 }
 
 struct B2 {
   virtual ~B2() = default;
 };
 
 struct D2 : B2 {
   virtual ~D2() = default;
   virtual void g() { /* ... */ }
 };
 
 void f2() {
   B2 *b = new D2; // Corrected the dynamic object type.
 
   // ...
   void (D2::*gptr)() = &D2::g; // Moved static_cast to the next line.
   (static_cast<D2 *>(b)->*gptr)();
   delete b;
 }
 
 struct B3 {
   virtual ~B3() = default;
 };
 
 struct D3 : B3 {
   virtual ~D3() = default;
   virtual void g() { /* ... */ }
 };
 
 static void (D3::*gptr3)(); // Not explicitly initialized: defaults to nullptr. Nonncompliant
 void call_memptr(D3 *ptr) {
   (ptr->*gptr3)();
 }
 
 void f3() {
   D3 *d = new D3;
   call_memptr(d);
   delete d;
 }
 
 struct B4 {
   virtual ~B4() = default;
 };
 
 struct D4 : B4 {
   virtual ~D4() = default;
   virtual void g() { /* ... */ }
 };
 
 static void (D4::*gptr4)() = &D4::g; // Explicitly initialized. Compliant
 void call_memptr(D4 *ptr) {
   (ptr->*gptr4)();
 }
 
 void f4() {
   D4 *d = new D4;
   call_memptr(d);
   delete d;
 }