成员函数调用中this实参与其他实参的求值顺序及空指针UB问题
问题解答
这段代码的行为属于未定义行为,无法保证estimate()会在访问model之前被调用,具体原因如下:
核心原因:求值顺序的不确定性
对于表达式model->set(estimate(model)),它包含两个关键操作步骤:
- 步骤1:求值
model->set——需要通过->操作符解引用空指针model,这一步本身就违反了C++标准,属于未定义行为。 - 步骤2:求值实参
estimate(model)——调用函数检查model是否为空,为空则抛出异常。
不同C++版本的求值规则
- C++17之前:编译器可以自由选择先执行步骤1还是步骤2。如果先执行步骤1,会直接触发未定义行为;如果先执行步骤2,会抛出异常进入catch块。但标准没有规定固定顺序,因此整个表达式的行为是未定义的。
- C++17及之后:标准明确规定,函数调用的前缀表达式(即
model->set)会在所有实参表达式之前求值。这意味着会先执行步骤1的空指针解引用,直接触发未定义行为,estimate(model)根本不会被调用。
额外说明
即使set函数内部没有访问this指向的成员变量,通过空指针调用非虚成员函数本身就是C++标准定义的未定义行为,和函数内部逻辑无关。
修复方案
正确的做法是先调用estimate()完成指针检查,确认有效后再调用成员函数:
try { std::shared_ptr<Model> model; int x = estimate(model); // 先执行检查,空指针直接抛出异常 model->set(x); // 此时model必然非空,调用安全 } catch (const std::runtime_error& e) { std::cout << e.what(); }
内容的提问来源于stack exchange,提问作者mentalmushroom
相关产品推荐
相关产品推荐

