Pregunta

Beginner's question:

Class Quote {
    public:
    /* ..... */

    virtual Quote* clone() const & {return new Quote(*this);}

    virtual Quote* clone() && {return new Quote(std::move(*this));} // (***)

    /* ..... */
}

Objects allocated by new are in the free-store. *this is whatever object that calls clone() and is not necessarily a dynamically-allocated object.

How does the move mechanism work if the moved-from and moved-to objects are in different memory areas? Or perhaps they're never really in different areas and I'm missing something?

From what I understand, the move constructor creates new overheads that link to the data/memory part of the moved-from object. The data itself is not moved/changed. How does this work in the above case? If it works the same way then after new runs wouldn't we have a dynamically-allocated object that sit outside free-store (wherever *this is located?) Is this somehow resolved by std::move()? I'm not exactly sure how/why std::move() work besides that it force-returns an rvalue reference to a named object making it possible to move from that object.

¿Fue útil?

Solución

From what I understand, the move constructor creates new overheads that link to the data/memory part of the moved-from object. The data itself is not moved/changed.

Not true. A typical move constructor ((I emphasize typical because a move constructor can really do anything the class writer wants it to do) will "steal" resources which another object owns remotely (e.g. a dynamically allocated array), by reassigning handles (e.g. a pointer to a dynamically allocated array)

When I say the resource is owned remotely, I mean it is not actually a data member of the class. The handle, however, is a data member of the class. The handle refers to the resource. The moved to object and the moved from object have distinct addresses and data members. Their data is able to be moved efficiently because it is not actually part of the class, it is referred to by the handle. The handle, unlike the resource, is small, and cheap to copy. "Moving" is actually copying handles from a source object to a destination object, then nullifying the handles in the source object so that its destructor doesn't destroy the resource.

How does the move mechanism work if the moved-from and moved-to objects are in different memory areas?

(Again I am speaking of a typical move constructor) It's irrelevant. Wherever they happen to be stored, they still have the same memory layout. The handles are modified exactly the same. The resource will be released when the destructor of the moved-to object is called (unless that object too is moved from). That means either when the object goes out of scope, if it is on the stack, or when delete is called on a pointer pointing to it, if it is on the free-store. (There are other possibilities, but those two are obviously the most common)

Otros consejos

A move does not move everything. Builtin data types like ints and pointers, for example can't be moved, they just can be copied. Moving is pure semantics. Best example is a std::vector or a std::string. Both typically contain a pointer to some dynamically allocated memory and some other variables. Said memory semantically belongs to the vector object, meaning it has to free the memory, it may alter its contents, it has control over it and is the only one to do so. The common term is "the vector has ownership of the allocated memory".
Now, when you copy a vector, the original will keep that ownership, and the copy will have to allocate it's own memory. In contrast, when you move a vector, the move-constructed new vector is allowed to steal the allocated memory, taking over the ownership of the resource the original vector once posessed. This can be done because the original vector is about to go out of scope anyways, and it does not need that resource any more.
However, the actual data members of the moved vector are not moved themselves. Since they are pointers and maybe ints, they can only be copied. After that has been done, the pointers and ints in the original get changed in a way that semantically ends its ownership of the allocated memory.

In short: moving is a semantic thing, on the lower technical level it is mostly a copy and setting the original to zero.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top