Move constructor/assignment operator

A move cotr/assignment optr is called when there's an rvalue reference (a temporary object) assigned to an lvalue. For instance I've defined my move semantics the following way:

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
template <typename T>                                              // Move constructor
myVec<T>::myVec(myVec&& a) noexcept : elem(a.elem), sz(a.sz)
{
    cout << "Move constructor is called.\n";
    a.elem = nullptr;
    a.sz = 0;
}

//*****************************************************
template <typename T>                               // Move assignment
myVec<T>& myVec<T>::operator=(myVec&& a) noexcept
{
    cout << "Move assignment is called.\n";
    if (this != &a)
    {
        delete[] elem;
        elem = a.elem;
        sz = a.sz;
        a.elem = nullptr;
        a.sz = 0;
    }
    return *this;
}

//***********************************************

int main() try
{
    myVec<int> vi1;
    myVec<int> vi2(10);
    myVec<int> vi3{ 2, 3, 4, 5 };
    myVec<int> vi4 = vi3;
    myVec<int> vi5 = myVec<int>{ 6,8 };
    vi5 = myVec<int>{ 16,28 };

    cin.get();
    return 0;
}


In main(), the move constrcutor is not called! (On line 33)
Last edited on
The code you posted won't compile.

Post the smallest possible complete program that we can test.

Make sure you post all the required code, ie follow the rule of 3/5.

Here you are, line 189

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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#include <iostream>
#include <stdexcept>

template <typename T>
class myVec {

public:
	myVec() { std::cout << "Default constructor is called.\n"; } // Default constructor
	myVec(size_t);  explicit // Ordinary constructor
	myVec(const std::initializer_list<T>&);  // Initializer list constructor
	myVec(const myVec&);  // Copy Constructor
	myVec<T>& operator=(const myVec&);  // Copy Assignment
	myVec(myVec&&);  // Move Constructor
	myVec<T>& operator=(myVec&&);  // Move Assignment

	T& operator[](int n) { return elem[n]; } // for non-const vectors
	const T& operator[](int n) const { return elem[n]; }  // for const vectors

	~myVec() { std::cout << "Destructor is called.\n"; delete[] elem; }  // Destructor - Release recources

	auto size() const { return sz; }

	template <typename U>
	void swap(myVec<U>& sp) { std::swap(sz, sp.sz); std::swap(elem, sp.elem); }

	template<typename U>
	friend std::ostream& operator<<(std::ostream& os, const myVec<U>& vec);

	void reserve(const size_t);
	void resize(const size_t);
	void push_back(T);

private:
	size_t sz{};
	size_t space{};
	T* elem{};
};

//******************************************************************

template<typename U>         // the '<<' operator overloading for the vector
std::ostream& operator<<(std::ostream& os, const myVec<U>& vec)
{
	for (size_t i = 0; i < vec.sz; i++)
		os << vec.elem[i] << " ";

	return os;
}
//******************************************************

template <typename T>                           // Ordinary constructor
myVec<T>::myVec(size_t size) : sz{ size }, space{ size }, elem{ new T[size] }
{
	std::cout << "Ordinary constructor is called.\n";
	//elem.reset(new T[size]);
}

//************************************************************

template<typename T>   // Initializer list constructor
myVec<T>::myVec(const std::initializer_list<T>& lst) : sz{ lst.size() }, space{ lst.size() }, elem{ new T[sz] }
{
	std::copy(lst.begin(), lst.end(), elem);
	std::cout << "Initializer list constructor is called.\n";
}

//********************************************

template<typename T>                 // Copy Constructor
myVec<T>::myVec(const myVec& arg) : sz{ arg.sz }, space{ arg.sz }, elem{ new T[sz] }
{
	std::copy(arg.elem, arg.elem + arg.sz, elem);
	std::cout << "Copy constructor is called.\n";
}

//***************************************************

template<typename T>           // Copy Assignment
myVec<T>& myVec<T>::operator=(const myVec& arg)
{
	if (this == &arg) return *this;

	if (arg.size() <= space) {
		std::copy(arg.elem, arg.elem + arg.sz, elem);
		sz = arg.sz;
		return *this;
	}

	T* p = new T[arg.sz];
	std::copy(arg.elem, arg.elem + arg.sz, p);
	delete[] elem;
	elem = p;
	sz = arg.sz;
	space = arg.space;
	std::cout << "Copy assignment is called.\n";
	return *this;
}

//****************************************

template<typename T>        // Move constructor
myVec<T>::myVec(myVec&& arg)
{
	sz = arg.sz; 
	elem = arg.elem;
	space = arg.space;
	arg.sz = 0;
	arg.space = 0;
	arg.elem = nullptr;
	std::cout << "Move constructor is called.\n";
}

//******************************

template<typename T>                // Move assignment
myVec<T>& myVec<T>::operator=(myVec&& arg)
{
	if (this == &arg) return *this;

	elem = nullptr;
	sz = arg.sz;
	space = arg.space;
	elem = arg.elem;
	arg.sz = 0;
	arg.space = 0;
	arg.elem = nullptr;
	std::cout << "Move assignment is called.\n";
	return *this;
}

//*******************************************************

template<typename T>    // The reserve function
void myVec<T>::reserve(const size_t newalloc)
{
	if (newalloc <= space) return;
	T* p = new T[newalloc];
	std::copy(elem, elem + sz, p);
	delete[] elem;
	elem = p;
	space = newalloc;
}

//*********************************

template<typename T>   // The resize function
void myVec<T>::resize(const size_t newsize)
{
	reserve(newsize);
	for (size_t i; i < newsize; ++i) elem[i] = 0;
	sz = newsize;
}


//******************************************

template<typename T>       // The push back function 
void myVec<T>::push_back(T d)
{
	if (space == 0)
		reserve(8);
	else if (sz == space) 
		reserve(2 * space);

	elem[sz] = d;
	++sz;
}

//***********************************************

int main() try
{
	myVec<int> vi1;
	myVec<int> vi2{ 10 };
	myVec<int> vi3{ 2, 3, 4, 5 };
	myVec<int> vi4 = vi3 ;
	
	vi1.push_back(12);
	vi1.push_back(14);
	
	vi3[3] = vi1[1];

	std::cout << vi1 << '\n';
	std::cout << vi2 << '\n';
	std::cout << vi3 << '\n';
	std::cout << vi4 << '\n';

	vi3 = myVec<int>{ 20 };
	auto vi5 = myVec<int>{ 30 };

	std::cout << vi3 << '\n';
	std::cout << vi5 << '\n';

	std::cin.get();
	return 0;
}

catch (std::invalid_argument& e)
{
	std::cerr << e.what() << "\n";
	abort();
}
catch (std::bad_alloc& e)
{
	std::cerr << e.what() << "\n";
	abort();
}
catch (...)
{
	std::cerr << "Something went wrong\n";
	abort();
}


No massage as "Move constructor is called.\n" is printed on the output when the program runs.
Last edited on
What line do you expect the move constructor to be called?

Perhaps some other constructor is being called? Maybe when you expect move you're getting the Initialize being called.

Perhaps you should add some print statements in main() to show what is being printed?

Default constructor is called.
Initializer list constructor is called.
Initializer list constructor is called.
Copy constructor is called.
12 14
10
2 3 4 14
2 3 4 5
Line 318: Initializer list constructor is called.
Move assignment is called.
Destructor is called.
Line 320: Initializer list constructor is called.
20
30
Destructor is called.
Destructor is called.
Destructor is called.
Destructor is called.
Destructor is called.


Note line 318 is right before the "vi3 = myVec<int>{ 20 };" line, and line 320 is right after that line.


the move constrcutor is not called!
Yes, this is commonly known as "copy elision". Which applies to move semantic as well. See:

https://en.cppreference.com/w/cpp/language/copy_elision
Topic archived. No new replies allowed.