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

探究Clang对多态对象typeid操作的副作用警告原因

关于Clang -Wpotentially-evaluated-expression警告的深层理解

本文并非询问如何规避下述警告(可提前存储为引用或用dynamic_cast替代typeid),而是旨在理解该警告存在的根本原因及其防护目标。

代码示例

#include <memory>
#include <iostream>

struct A { virtual ~A() = default; };

struct B : A { };

A *get_pa() { 
    static A static_a{};
    return &static_a; 
}

int main() {
    std::shared_ptr<A> pa1 = std::make_shared<B>();
    A *pa2 = new B{};

    //1) warning: will be evaluated
    std::cout << typeid(*pa1).name() << '\n';         

    //2) okay
    std::cout << typeid(pa1.get()).name() << '\n';  
    
    //3) okay    
    std::cout << typeid(*pa2).name() << '\n';               

    //4) warning: will be evaluated
    std::cout << typeid(*new A{}).name() << '\n';
    
    //5) warning: will not be evaluated
    std::cout << typeid(new A{}).name() << '\n'; 

    //6) warning: will be evaluated
    std::cout << typeid(*get_pa()).name() << '\n';  

    //EDIT 1:
    //7) okay
    std::cout << typeid(get_pa()).name() << '\n';
}

Clang编译触发的警告

warning: expression with side effects will be evaluated despite being used as an operand to 'typeid' [-Wpotentially-evaluated-expression]
    std::cout << typeid(*pa1).name() << '\n';
                        ^

初步理解

  • typeid在这些场景下会实际求值表达式,而开发者可能未意识到这一点;
  • 表达式涉及多态引用,即便当前类无副作用,其子类可能存在副作用;
  • *pa1等价于*pa1.get(),会调用返回指针的函数,开发者可能未注意到解引用被重载。

核心疑问

  • 所有触发警告的表达式(除示例5)均对A*指针解引用,解引用指针为何会产生副作用?为何未解引用的表达式不会触发警告?

额外观察

  • 示例6和7显示,编译器关注的是解引用操作的潜在副作用,而非返回多态对象指针的表达式;
  • 解引用原生指针或智能指针无差异,并非与重载解引用操作相关;
  • 若将A改为非多态(移除虚析构函数),则不会触发该求值警告(示例4、5仍会触发相反警告);
  • 示例3与上述观察矛盾,若问题出在解引用,指针是否具名不应影响警告触发;
  • 目前关于警告触发原因及时机的解释存在不一致性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 10:56:06