You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何调用成员函数不会触发该对象的ODR使用?

为什么调用成员函数不会触发对象的ODR使用?

首先先把cppreference里提到的规则和示例摆出来:

若非内联变量(C++17起)的初始化被延迟至main/线程函数的第一条语句之后进行,则其会先于对与该变量同翻译单元中定义的任何静态/线程存储期变量的首次ODR使用完成初始化。

对应的示例代码:

// - File 1 -
#include "a.h"
#include "b.h"
B b;
A::A(){ b.Use(); }

// - File 2 -
#include "a.h"
A a;

// - File 3 -
#include "a.h"
#include "b.h"
int main() {
    // 程序入口
}

咱们先搞明白核心问题:什么是ODR使用,以及为什么这里调用b.Use()不算对b的ODR使用。

先理清ODR使用的定义

说白了,一个对象的ODR使用,是指在代码中对这个对象的使用场景需要它的完整定义存在——比如读取它的值、获取它的地址,或者把它绑定到引用上。这种场景下,编译器/链接器需要找到对象的实际定义,并且对象必须已经完成初始化才能保证行为合法。

为什么调用成员函数不算ODR使用?

当你调用b.Use()时,编译器会把这个代码转换成类似B::Use(&b)的形式——也就是隐式把b的地址作为this指针传递给成员函数。但这里的关键在于:

  • 如果Use()是非虚成员函数,并且这个函数没有访问B类的任何非静态数据成员,也没有调用任何会访问这些成员的函数,那么传递&b这个操作并没有真正“使用”b的定义。
  • 因为非虚成员函数的代码是独立于对象存在的,即使b还没完成初始化,调用这个函数也不会有问题——毕竟函数里根本没用到对象的任何状态。

根据C++标准的ODR规则,这种场景下的对象使用并不构成ODR使用:它既没有读取b的值,也没有依赖b的地址做除了传递给成员函数之外的事情,而成员函数又没有用这个地址去访问对象的内部。

回到示例里的情况:b是File1中的静态变量,它的初始化可能被延迟到main之后执行。而a是File2中的静态变量,初始化时会调用A::A(),进而调用b.Use()。因为这个调用不算对b的ODR使用,所以cppreference里提到的规则就不适用——b的初始化不需要提前到a初始化之前完成,程序也不会出现未定义行为。

内容的提问来源于stack exchange,提问作者choxsword

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:31:46