0

My question contains two parts:

  1. Does function static_cast<Т>(arg) alter the innards of arg? Obviously not, according to such code:

    float i1 = 11.5;
    int x = static_cast<int>(i1);
    std::cout << i1<<std::endl;   //11.5
    std::cout << x<<std::endl;    //11
    
  2. Why does such code:

    std::string s1 = "123";
    std::string s2 = std::move(s1);
    std::cout << s1 << std::endl;  //empty
    std::cout << s2 << std::endl;  //123
    

    where std::move() is using only a static_cast to r-value:

    template<typename _Tp>
    constexpr typename std::remove_reference<_Tp>::type&&
    move(_Tp&& __t) noexcept
    { return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }
    

    makes s1 an empty string?

I guess, it is because of using the move constructor of string after s2 =. It must wipe the initial string by equating to nullptr or 0 all of the data in the string object. While std::move() by itself is only returning rvalue. Is it correct?

I know my question is a duplicate of something like static_cast to r-value references and std::move change their argument in an initialization, but I have not found a clear explanation.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Max Popov
  • 357
  • 2
  • 12
  • 5
    It's not `std::move` or `static_cast` that changes `s1`, it's `string(string&&)` constructor used to initialize `s2`. Which is kinda the whole point of move semantics. See for yourself - if you just write `std::move(s1);` on its own, `s1` will remain unchanged. – Igor Tandetnik Aug 01 '21 at 13:19

2 Answers2

0

While reading your question, I had a sense of feeling that you already understood what's happening and yet wanted it to be confirmed.

I guess, it is because of using move constructor of string after s2 =. It must wipe the initial string by equating to nullptr or 0 all data in string object. While std::move() by itself is only returning rvalue.

Is it correct?

Yep, you got it right. That's basically what's happening.

std::move doesn't move and doesn't change any state of the object "by itself". It just casts a given object's type as a rvalue reference.

It's a constructor of std::basic_string that eliminates s1 in your example.

In cppreference, it gives you a brief detail of what it does:

...Constructs the string with the contents of other using move semantics. other is left in valid, but unspecified state.

Try writing a sample code like this to prove your point:

std::string s = "Hello World";
(void)std::move(s); // (void) is there to discard the warning message.
std::cout << s;

You can see s have not changed at all.

Dean Seo
  • 5,486
  • 3
  • 30
  • 49
  • One little question about default move constructor: Does he only apply std::move() to each field or equates old pointers to nullptr too? – Max Popov Aug 18 '21 at 12:49
  • 2
    @MaxPopovsky The *after-moved object* is **not** guaranteed to be empty or `nullptr`. – Dean Seo Aug 18 '21 at 13:06
0
template<typename Tp>
constexpr typename 
std::remove_reference<Tp>::type&&
move(Tp&& _t) noexcept
{ return static_cast<typename std::remove_reference<Tp>::type&&>(_t); }

std::move() returns a new reference to an rvalue entity (rvalue reference), even if initial entity is an lvalue. It is made by using universal reference Tp&& as input argument which can refer to lvalue or rvalue expressions, type_traits function std::remove_reference which removes all refrerence from entity, and by turning it to rvalue-ref by adding && to it in static_cast at the end.

Any reference is just an another name of the entity it refers to, and we can alter that entity through this reference. In some approximation reference is handled as an object it refers to.

So, std::move() returns a new reference to an rvalue entity, and accordingly to listed upper reasoning, this rvalue reference is perceived as an rvalue entity. So result of std::move() might be feeded into appropriate constructors or functions just as rvalue argument. And accordingly to reference ability to change the entity it refers to, we can change initial entity, even if it is an lvalue (set to zero ptr etc.)

Max Popov
  • 357
  • 2
  • 12