Can move semantics be used if the class member is not a pointer.

Hi ppl :)
I was recently trying to understand move semantics of c++ 11 and found that most of the examples available online demonstrate this using a class member that is of pointer type. Like below :

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
58
59
60
61
62
63
64
65
#include <iostream>
#include <string.h>

class Str
{
    private:
        char *str;
        friend Str operator+(const Str&, const Str&);

    public:
        Str() = default;

        Str(const char* s)
        {
            str = new char[strlen(s) + 1];
            strcpy(str, s);
        }

        Str(Str&& s)  //Move constructor
        {
            std::cout << "move constructor called\n";
            str = s.str;
            s.str = nullptr;
        }

        virtual ~Str()
        {
            delete [] str;
        }

        int size() const
        {
            return strlen(str);
        }

        void showStr()
        {
            for (int i {0}; i < str[i] != '\0'; ++i)
                std::cout << str[i];
            std::cout << std::endl;
        }
};

Str operator+(const Str& a, const Str& b)
{
    char* c = new char[a.size() + b.size() + 1];
    strcpy(c, a.str);
    strcpy(c + a.size(), b.str);

    return Str(c);
}

void f(Str s)
{
    s.showStr();
}

int main()
{
    Str s1{"hello "};
    Str s2{"everyone"};
    f(std::move(s1 + s2)); //will invoke Move constructor

    return 0;
}


I am looking for an example where the move semantics is applied for a non pointer member, like a vector.

To be precise, how would we write move constructor if "str" were a vector instead of char* above were a vector.

 
Test(std::vector<int>&& vec) ??


Thanks for the help :)
Last edited on
1
2
3
4
Test(std::vector<int>&& vec)
:	str(std::move(vec))
{
}
Thanks Peter87 :)
To note, the call to move in f(std::move(s1 + s2)) is redundant, because the expression s1+s2 is an rvalue.

In fact, it's actually worse than redundant, because the explicit move prevents copy elision, forcing a move or copy where neither a move nor copy is necessary. This isn't just an optimization : without that move() call, no copy or move operation occurs, even conceptually.

Consider:
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
58
59
60
61
62
63
64
65
66
67
68
69
#include <utility>
#include <iostream>

struct noisy
{
  explicit noisy(int v = 0)
    : value(v)
  {
    std::cout << value << " : construct\n";
  }
  noisy(const noisy &that)
    : value(that.value)
  {
    std::cout << value << " : copy construct\n";
  }
  noisy(noisy &&that)
    : value(that.value)
  {
    std::cout << value << " : move construct\n";
  }
  noisy &operator=(const noisy &that)
  {
    value = that.value;
    std::cout << value << " : copy assign\n";
    return *this;
  }
  noisy &operator=(noisy &&that)
  {
    value = that.value;
    std::cout << value << " : move assign\n";
    return *this;
  }
  ~noisy()
  {
    std::cout << value << " : destroy\n";
  }

  int value;
};

noisy
operator+(noisy const &a, noisy const &b)
{
  return noisy{ a.value + b.value };
}

void
f(noisy n)
{
  std::cout << n.value << "\n";
}

int
main()
{
  std::cout << "Without std::move:\n";
  {
    noisy a{ 24 };
    noisy b{ 18 };
    f(a + b);
  }

  std::cout << "\n\nWith std::move:\n";
  {
    noisy a{ 24 };
    noisy b{ 18 };
    f(std::move(a + b));
  }
}
Without std::move:
24 : construct
18 : construct
42 : construct
42
42 : destroy
18 : destroy
24 : destroy


With std::move:
24 : construct
18 : construct
42 : construct
42 : move construct
42
42 : destroy
42 : destroy
18 : destroy
24 : destroy

http://coliru.stacked-crooked.com/a/bee5dc66c4002acb
Last edited on
Topic archived. No new replies allowed.