p_tan's blog

勉強日記です。ツッコミ大歓迎

データメンバに触らなければヌルポインタの参照外しを行なっても実行時エラーにならない

恥ずかしながら知らなかった。
ヌルポインタの参照外しを行ったらすぐにセグメンテーションフォールト等で落ちるもんだと思い込んでたけど、データメンバに触らなければ実行できてしまうようだ。
規格上認められてるのか、それとも未定義動作なのか。

#include <iostream>
using namespace std;

class X {
    int member;
public:
    X(int m):member(m){}
    // データメンバに触らないメンバ関数
    void func(){
        // member = 1;    // この行のコメントを外すとセグフォ
        cout << "X::func()\n";
    }
};

int main(){
    X *p = nullptr;
    p->func();
    (*p).func();
    return 0;
}

出力

X::func()
X::func()

これに関連して、ポインタと参照を併用する場合に参照がNULLを指す事が起こったりする。

class X {
    int member;
public:
    void set(int val){
        member = val;
    }
};

void func(X&);  // 宣言

int main(){
    X *p = nullptr;
    func(*p);  // ヌルポインタの参照外しで関数funcを呼び出し
        // この時点ではセグフォは起きない
    return 0;
}

void func(X& x){  // 定義
    x.set(1);    // ここでセグフォ
}

X::set()を呼び出してるところがさらに関数の深いネストの奥だったりすると、再現性の無いバグに悩まされるかもしれない。ポインタと参照を併用する場合は気を付けよう。