探究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
相关产品推荐
相关产品推荐

