Why is movement semantics necessary to exclude temporary copies?

So, my understanding of move semantics is that they allow you to redefine functions for use with temporary values ​​(rvalues) and avoid potentially expensive copies (by moving a state from an unnamed temporary to your lvalue name).

My question is: why do we need special semantics? Why was the C ++ 98 compiler unable to delete these copies because it compiler determines whether the given expression is lvalue or rvalue? As an example:

void func(const std::string& s) {
    // Do something with s
}

int main() {
    func(std::string("abc") + std::string("def"));
}

Even without the C ++ 11 move semantics, the compiler must still determine that the expression passed to func()is an rvalue, and therefore, a copy from a temporary object is not needed. So why is this difference? This application of move semantics seems to be essentially a copy or other similar compiler optimizations.

As another example, why do I need to have code like the one below?

void func(const std::string& s) {
    // Do something with lvalue string
}

void func(std::string&& s) {
    // Do something with rvalue string
}

int main() {
    std::string s("abc");

    // Presumably calls func(const std::string&) overload
    func(s);

    // Presumably calls func(std::string&&) overload
    func(std::string("abc") + std::string("def"));
}

It seems that overloading const std::string&can handle both cases: lvalues ​​as usual, and rvalues ​​as a reference to const (since temporary expressions are sorts by definition). Since the compiler knows when an expression is an lvalue or rvalue value, it can decide whether to exclude a copy in the case of an rvalue.

, , , pre-++ 11?

+4
4

.

, , , . .

++ . - , , . " " . " ", , , - , , , . , , , ++.

- . , " ", , .

- , . ++ 11 ++ 14, , " ", . ctor , - .

, " " - ++ 17, , , .

ellision " ". , () , . ellision .

, , , pre-++ 11?

" ". . -O0 gcc clang - , , - , "" , " ", , .

, . , . , , , , . , . , , , .

, " " , , , , , , , , . , , , , factory. , , . .

+8

elision . , , . "-" . . "-" - , .

:

class Bar {

    std::vector<int> foo;

public:

    Bar(const std::vector<int> &bar) : foo(bar)
    {
    }
};

std::vector<int> foo();

int main()
{
     Bar bar=foo();
}

, , .

:

    Bar(std::vector<int> &&bar) : foo(std::move(bar))
    {
    }

main() . , - .

:

Bar foo();

int main()
{
     Bar bar=foo();
}

. .

: . "".

+3

, ++:

++ 11 , , func(), rvalue, , , .

++ 98. A const& . const, . , , const string&, .

func. .

, , ?

. rvalue-reference, . , const&, ++ 98.

:

, , (rvalues) ( lvalue).

.

- ; , std::move, lvalues. - . , lvalues:

std::unique_ptr<T> p = ...
std::unique_ptr<T> other_p = std::move(p);
assert(p == nullptr); //Will always be true.

unique_ptr, unique_ptr. ; .

, , . , lvalue ( std::move ).

+2

, . , / . , , . move ctor . ctor , -, .

. :

  • T&&, , . Dot. . ++ 03 - . , . .
  • rvalue. , .

:

void Func(std::vector<MyComplexType> &v)
{
    MyComplexType x;
    x.Set1();          // Expensive function that allocates storage
                       // and computes something.
    .........          // Ton of other code with if statements and loops
                       // that builds the object x.

    v.push_back(std::move(x));  // (1)

    x.Set2();         // Code continues to use x. This is ok.        
}

, (1) ctor, . , , .

+1

Source: https://habr.com/ru/post/1662917/


All Articles