看看这段代码:
struct Data {
};
struct Init {
Data *m_data;
Init() : m_data(new Data) { }
~Init() {
delete m_data;
}
};
class Object {
private:
const int m_initType;
Data *m_data;
public:
Object(const Init &init) : m_initType(0), m_data(init.m_data) { }
Object(Init &&init) : m_initType(1), m_data(init.m_data) { init.m_data = nullptr; }
~Object() {
if (m_initType==1) {
delete m_data;
}
}
};
void somefunction(const Object &object); // it is intentionally not defined
void callInitA() {
Init x;
somefunction(x);
}
void callInitB() {
somefunction(Init());
}
由于Object::m_initType
是const,它在构造函数之后不会改变。因此,理论上,在callInitA
和callInitB
中,编译器在内联m_initType
时知道~Object()
的值。但是,gcc和clang fails to apply都是这种优化,并且都会检查m_initType
的值。
为什么?是否有针对此优化的语言规则,或者编译器不进行此类优化?
(这个问题与this密切相关,但这是一个更具体的问题,我希望我能得到答案)
答案 0 :(得分:3)
要回答是否有禁止此类优化的语言规则,请参阅此处
除了可以修改声明为mutable的任何类成员之外,任何在其生命周期内修改const对象的尝试都会导致未定义的行为。
理论上,优化器可以安全地假设m_initType
在初始化后永远不会改变。这当然可以用来推断~Object
中的分支是否会在编译时被采用。
也就是说,只要观察到的行为保持不变,优化者就可以自由地做任何事情,他们也可以自由地忽略const
。为了使优化器更复杂,在混合中有一个前向声明但未定义的函数,优化器可能在此之后就放弃了对信息做任何有用的事情。
Comparison of defined vs undefined function
如果稍后定义该函数,gcc和clang都会优化一切。但请注意,在这种特殊情况下,即使没有任何const
,它们也会still do this。
答案 1 :(得分:0)
在您的示例中没有内联对象析构函数,并且您有2个调用,其中一个m_initType是1而另一个是0.因此编译器必须支持这两个版本。 此外,我认为您的实际代码比您的示例稍微复杂一些,因此编译器可能会认为内联整个析构函数代码比使用单个“if”内部的通用版本更昂贵。