Confusion regarding rvalue references

Pages: 12
But you can't emplace_back on a C-style array because C-style arrays have a fixed size. But maybe I'm misunderstanding?

I'm talking about int* arr = new int[2] or the like. I now think I understand what emplace_back does.

You're using std::move, so it will move it. There is no copy in either of those examples.
It's worth noting that std::move supplies you with an rvalue reference to the argument fed to it. It does not mean that object will be moved. There could very well be copies in either of those examples, depending on the type of T.

If I understand it correctly, this means the following:
1
2
3
4
String str;
str = std::move("Hello!"); // This will move "Hello!" since it is an rvalue
String str2("Hello!");
str = std::move(str2); // This will copy "Hello!" from [str2] since it is an lvalue 

Is this right?

Though the second example is superior because you move construct, which is better than default constructing only to move assign immediately after.

So, using void PushBack(T value) { ptr[x] = new T(std::move(value)); } will do the following:
1
2
3
4
Array<String> arr;
String str("Hello!");
arr.PushBack(str); // Will create a copy of [str] directly in [arr]
arr.PushBack("Hello!"); // Will move "Hello!" directly to [arr] 

Is this correct?

Sorry for taking your time; I really appreciate the help.
Last edited on
If I understand it correctly, this means the following:

1
2
String str;
str = std::move("Hello!"); // This will move "Hello!" since it is an rvalue 

No move here. There is no std::string::operator= which takes an rvalue reference to a pointer to const char (because, why would there be?) "Hello!" is not an object of type std::string.


1
2
String str2("Hello!");
str = std::move(str2); // This will copy "Hello!" from [str2] since it is an lvalue  

This is a move. As I mentioned before std::move supplies you with an rvalue reference to whatever argument you've fed to it. str = str2; would result in a copy.

"Hello!" is not an object of type std::string.
Sorry, I meant std::string("Hello!").

This is a move. As I mentioned before std::move supplies you with an rvalue reference to whatever argument you've fed to it. str = str2; would result in a copy.
1
2
3
4
5
6
7
8
void operator=(String s)
{ str = std::move(s); }

int main()
{
  String str, str2("Hello!");
  str = str2; // This will copy "Hello!" from [str2] since it is an lvalue (?)
}
Is this correct, then?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
#include <utility>
#include <string>

template< typename T, std::size_t N > void assign( T(&arr)[N], std::size_t pos, const T& value )
{ if( pos < N ) arr[pos] = value ; /* copy assign lvalue*/ }

template< typename T, std::size_t N > void assign( T(&arr)[N], std::size_t pos, T&& value )
{ if( pos < N ) arr[pos] = std::move(value) ; /* move assign rvalue*/ }

template< typename T, std::size_t N > void assign_v2( T(&arr)[N], std::size_t pos, T value )
{ if( pos < N ) arr[pos] = std::move(value) ; /* move assign parameter passed by value*/ }

template< typename T, std::size_t N, typename U > void assign_v3( T(&arr)[N], std::size_t pos, U&& value )
{ if( pos < N ) arr[pos] = std::forward<U>(value) ; /* perfect forwarding */ }

struct A
{
    A() = default ;
    A( const char* cstr ) : str(cstr) {}

    A( const A& that ) : str(that.str)
    { std::cout << "copy construct\n" ; }

    A( A&& that ) noexcept : str( std::move(that.str) )
    { str.swap(that.str) ; std::cout << "move construct\n" ; }

    A& operator= ( const A& that )
    { str = that.str ; std::cout << "copy assign\n" ; return *this ; }

    A& operator= ( A&& that ) noexcept
    { str.swap(that.str) ; std::cout << "move assign\n" ; return *this ; }

    std::string str ;
};

int main()
{
    A arr[20] ; // 20 strings are default-constructed
    A hello( "hello" ) ;

    assign( arr, 0, hello ) ; // lvalue, copy assign
    std::cout << "------------\n" ;
    // hello can still be used here
    assign( arr, 1, A( " world!" ) ) ; // rvalue, move assign
    std::cout << "------------\n\n" ;

    assign_v2( arr, 2, hello ) ; // lvalue, copy construct, followed by move assign the copy
    std::cout << "------------\n" ;
    assign_v2( arr, 3, A( " world!" ) ) ; // rvalue, move assign (copy elision)
    std::cout << "------------\n\n" ;

    assign_v3( arr, 2, hello ) ; // lvalue, copy assign
    std::cout << "------------\n" ;
    assign_v3( arr, 3, A( " world!" ) ) ; // rvalue, move assign
    std::cout << "------------\n" ;
}

http://coliru.stacked-crooked.com/a/a7b8cd2c8587178e
http://rextester.com/MRTT40289
Last edited on
That's... quite the explanation! Thank you, I think I understand now.
Topic archived. No new replies allowed.
Pages: 12