Search code examples
c++stackmove

move semantics with local variables


I was wondering about the following code taken from this example:

Is it possible to std::move local stack variables?

struct MyStruct
{
    int iInteger;
    string strString;
};
    
void MyFunc(vector<MyStruct>& vecStructs)
{
    MyStruct NewStruct = { 8, "Hello" };
    vecStructs.push_back(std::move(NewStruct));
}
    
int main()
{
    vector<MyStruct> vecStructs;
    MyFunc(vecStructs);
}

I understand how std::move() works on a basic level, but there's something under the hood that doesn't make sense to me.

If, for example, NewStruct was created on the stack, locally, as in the example. If I used move semantics to save its data from being destroyed before exiting the function scope, thus NewStruct being destroyed won't affect my data, which is great. But isn't this information still placed on the stack? If I were to expand my use of the stack again, why wouldn't this information be in danger of being overridden once the stack grew and wanted to write over where NewStruct data was originally created?

Adding a second example to maybe get my point across in a better manner:

    void MyFunc(vector<char*> &vecCharPointers)
    {
        char* myStr = {'H', 'e', 'l', 'l', 'o'};
        vecCharPointers.push_back(std::move(myStr));
    }

    int main()
    {
        vector<char*> vecCharPointers;
        char* cp = nullptr;
    }

Solution

  • If NewStruct was entirely on the stack, the moving it would be no more efficient than copying it. To create a new object with the same contents as NewStruct would require copying everything from the stack to wherever the new object is.

    Where move semantics are helpful are for objects that aren't entirely on the stack (or, to be more precise, don't have their entire contents stored in the object's fixed-size portion). For example, a std::string or a std::vector (or an object that contains them) will typically have a buffer that holds variable-length data that is allocated from the heap. Move semantics can transfer ownership of this buffer from the old object to the new object, saving the need to allocate a new buffer and copy the contents of the old buffer into it.