Question

The question is: where is temporary object allocated when returned by value? I.e., on stack, in dynamically allocated memory — what do compilers do in such cases?

I'm digging deep into the underlying logic in the move constructor idiom in C++03 as described in More C++ Idioms/Move Constructor, and the interesting part is how an object is returned:

struct foo {
    int values[100];
    ...
};

foo func() {
    foo ret;
    ... // assign value to ret
    return ret;
}

int main() {
    foo a(func());
    ...
    return 0;
}

The point between return ret; and a(func) clearly contains stack cleanup and further copy construction, but where is the temporary object stored before it is passed into copy constructor? Maybe, I oversaw the answer in search results, but still can't find an explanation.

EDIT:

Okay, the example may seem overly simple. In real applications, we could write something like that:

class Command {
public:
    Command();
    Command(const Command &);
    ...

private:
    CommandResponseType mResponseType;

    quint64    mId;
    QString    mName;
    quint16    mTypeCode;
    QDateTime  mDatetime;

    TParamList mParams;
};

Such a class is not POD, and compiler is likely not to optimize copy construction Command a(someInstanceOfOtherClass.getCommand("foo")); by simply allocating the value on stack. At least, copy construction of QString, QDateTime, and TParamList is involved.

If I understand correctly, getCommand() has __thiscall calling convention, which obligates the callee to clean up the stack on its own. The logic solution is to allocate the result in memory an return a pointer. I'll try different scenarios and see into assembly.

Was it helpful?

Solution 3

A simple example how an object can be constructed on stack is an implicit use of operator new in the non-allocating form, void* operator new (std::size_t size, void* ptr) throw():

class Foo {
public:
    Foo();
    Foo(const Foo &);
    ~Foo();
private:
    // data members
    ...
}

void bar() {
    Foo f1;
    // // Allocate sufficient memory on stack:
    // char f1[sizeof(Foo)];
    // // Call operator new on this memory and execute Foo's constructor
    // // with (this == f1):
    // operator new (sizeof(Foo),f1) Foo();
    ...

    // Or «non-optimized» case, with copy-constructor involved:
    Foo f2 = Foo();
    // char f2[sizeof(Foo)];
    // {
    //     // tmp is constructed as in the previous case:
    //     char tmp[sizeof(Foo)];
    //     operator new (sizeof(Foo),tmp) Foo();
    //     // And then f2 is constructed using Foo's copy-constructor:
    //     Foo::Foo(f2 /*this*/, tmp)
    // }
    // // Here, tmp must be destructed and popped from stack.
}

Links:

http://en.wikipedia.org/wiki/Return_value_optimization

OTHER TIPS

One possibility is that there's no temporary object at all if the compiler is clever enough to optimize this into an allocation (inside the stack frame of main()) and a move. If there is, that is most probably on the stack as well, but why don't you check the generated assembly?

When I write foo a(func()); the struct constructor is called, which is basically a function. This takes the argument func(). So the code will first calculate func() and push the return value to stack. Now foo() will take this value as argument. And implementation providers are free to do any kind of optimization here. Pls Correct me If I'm wrong.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top