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

MSVC中对象构造与成员函数内同指针检查结果矛盾问题问询

MSVC中对象地址检查的矛盾问题分析

以下是用于复现Visual Studio C++编译器问题的最简代码:

struct P {
    const P * s = nullptr;
    constexpr P() {}
    constexpr P(const P & p) : s(&p) {
        if (s == this) throw 0; // 从未触发
    }
    constexpr bool operator()() const {
        return s != this; // 按逻辑应始终为true?
    }
};

constexpr bool f(P p) {
    return p.s ? p() : f(p);
}

int main() {
    static_assert( f(P{}) ); // 在MSVC中失败,实际返回false
}

问题现象

P类的拷贝构造函数会记录源对象的指针s,构造时的s == this检查永远不会触发,说明拷贝后的新对象地址与源对象地址不同;但在operator()中执行相同的地址检查,却返回s == this的结果,导致static_assert断言失败。

原因分析

这是MSVC的constexpr求值实现bug:
在constexpr上下文处理值传递的参数拷贝时,MSVC错误地将拷贝构造生成的新对象地址与源对象地址视为同一地址。

具体流程中:

  1. 调用f(P{})时,初始传入的p是默认构造的对象,p.s为nullptr,因此会递归调用f(p),此时需要拷贝构造一个新的P对象。
  2. 拷贝构造时,s被赋值为源对象的地址,此时this指向新构造的对象,显然s != this,所以构造函数中的throw不会触发。
  3. 但MSVC在constexpr求值过程中,错误地将拷贝后对象的this指针与源对象的this指针判定为相同,导致operator()中s == this成立,最终返回false,触发断言失败。

而GCC、Clang等编译器的constexpr求值逻辑符合C++标准,能够正确区分拷贝前后的不同对象地址,因此operator()会返回预期的true,断言通过。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 09:11:01