Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why don't compilers optimize this out?

Tags:

c++

gcc

clang

Look at this code:

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());
}

As Object::m_initType is const, it doesn't change after constructor. So, in theory, in callInitA, and in callInitB, the compiler knows of the value of m_initType when it inlines ~Object(). However, both gcc and clang fails to apply this optimization, and both checks the value of m_initType.

Why is that? Is there some language rule against this optimization, or compilers just don't do this kind of optimization?

(This question is closely related to this, but it is a more specific question, I hope I can get an answer for this)

like image 959
geza Avatar asked Jul 02 '17 11:07

geza


1 Answers

To answer whether there is any rules in the language that forbids this kind of optimization, here's my take

From [dcl.type.cv]

Except that any class member declared mutable can be modified, any attempt to modify a const object during its lifetime results in undefined behavior.

And so in theory, the optimizer may safely assume m_initType will never change after initialization. This can of course be used to deduce whether the branch in ~Object will be taken at compile time.

That said, optimizers are free to do anything as long as the observed behaviour stay the same, so too are they free to ignore const. To make matters more complicated for the optimizer, there is an forward declared but not defined function in the mix, the optimizer probably just gave up after that to do anything useful with the information.

Comparison of defined vs undefined function

If the function is defined later on, gcc and clang both optimizes everything away. Note however, in this particular case, they will still do this even without any const.

This post might be of interest

like image 67
Passer By Avatar answered Sep 19 '22 05:09

Passer By