0

If a constructor B() is called to create a temporary object, e.g. in a call f(B().name()), will the construction of B always carried out, or are compilers permitted and able to optimize out unnecessary allocations that go along with object creation?

Specific example:

class A {
 public:
    virtual std::string name() = 0;
};

class B : public A {
 public:
    std::string name() final { return "MyClassName"; }
    // cannot be made static, because at some places we need
    // the polymorphic call from A-pointers
 private:
    int data;
    ...
    // members that require heap allocation
};

int main() {
    std::cout << "Class B is named " << B().name() << std::endl;
}

Will the last statement actually create an instance of B, including allocation of storage for B().data?

7
  • Non-static member functions always needs an object to be called on. Even if you don't use the object itself (the this pointer) in the function, the object still needs to exist. Commented Aug 5, 2020 at 8:42
  • 2
    Real question is "why does it matter to OP"? Maybe elaborate on your use case or concerns. Commented Aug 5, 2020 at 8:50
  • Do you care about whether it's legal in general, or whether some specific compiler will actually optimize it out in this specific code? Because for the latter, you could just check. Commented Aug 5, 2020 at 9:01
  • In common constructors do not have any return type not even void. If I add const to your function prototype (because it is), one cannot compile the code. Is it legal to do B().name() ?? Commented Aug 5, 2020 at 9:04
  • By the way, you return a reference to a temporary from a function. I also get a runtime error at B().name(). However, I wonder how this even could compile in the first place. Use a static variable in the function name(). Commented Aug 5, 2020 at 9:08

1 Answer 1

4

A compiler may completely remove a call to constructor just like any other function. While an instance of B is necessary for the code to be semantically correct, it doesn't mean that after compilation it needs to exist (as a piece of memory). Also remember that a call to constructor is not the same as allocation.

So as far as I understand, the question is whether heap allocation (as in usage of new/delete operators) can be removed by the compiler as well? Typically compilers have a hard time with side effect operations. However allocations seems to be an exception: Can the compiler optimize from heap to stack allocation? as long as new/delete operators are not overloaded.

A concerete example is this:

class A {
 public:
    virtual int get() = 0;
    virtual ~A() {};
};

class B : public A {
 public:
    int get() { return 5; }
    ~B() {
        delete ptr;
    }
 private:
    int data;
    int* ptr = new int;
};

int foo() {
    return B().get();
}

which under all the compilers I've tried (gcc and clang, X64, with full optimizations on) produces simple

foo():
        mov     eax, 5
        ret

with no allocations at all.

Sign up to request clarification or add additional context in comments.

2 Comments

Not with MSVC. Even for the others, I'm not quite sure how they're omitting the call to operator new since that could be defined in another translation unit. As one of the answers you linked to says, a compiler is allowed to elide multiple calls to operator new into one, but must still ultimately call it. Maybe the compiler writers feel that it's worth being slightly non-conformant for the speed improvement.
@ArthurTacca operator new has to be called if it is a non-replacable global function (i.e. overload?). Otherwise it can be totally removed. Or at least this is how I understand the linked post. Also I didn't check MSVC, I've updated the answer about compilers info.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.