I created a class, "ListElement", that contains as a single data variable an instance of the class "MyClass" which contains a dynamically allocated array.
For ListElement I created a default constructor which delegates to a right-value constructor that initializes an instance of MyClass.
For MyClass I created a constructor which initializes its array to an inputted value (and a default constructor which delegates to the one above with value 0). Furthermore, I included a copy and a move constructor.
I'm, however, mostly confused, why the move constructor is not called unless the datatype is casted as an r-value reference explicitly, although it is already passed as such (see below).
#include <iostream>
template <int arrSize>
class MyClass {
private:
// Data
int* a;
public:
//Constructor
MyClass(int value){
this->a = new int[arrSize];
for(unsigned int i = 0; i<arrSize; ++i){
a[i] = value;
}
std::cout << "MyClass created!" << std::endl;
}
MyClass(): MyClass(0){}
//Copy Constructor
MyClass(const MyClass<arrSize>& other){
this->a = new int[arrSize];
for(unsigned int i = 0; i<arrSize;++i){
a[i] = other.a[i];
}
std::cout << "MyClass copied!" << std:: endl;
}
//Move Constructor
MyClass(MyClass<arrSize>&& other){
this->a = other.a;
other.a = nullptr;
std::cout << "MyClass moved!" << std::endl;
}
//Destructor
~MyClass(){
delete[] this->a;
std::cout << "MyClass deleted!" << std::endl;
}
};
class ListElement {
public:
//Constructors
ListElement(MyClass<5>&& data) : data((MyClass<5>&&)data) {} // QUESTION
ListElement(): ListElement(MyClass<5>(1)){}
private:
//Data
MyClass<5> data;
};
int main() {
ListElement myZeroListElement{};
return 0;
}
Question: Why is the copy constructor called if I write for this line (see comments)?
ListElement(MyClass<5>&& data) : data(data) {}
"data" is a right-value reference, but the move constructor is only called when I explecitly cast it, so-to-say, again into a right-value reference like this:
ListElement(MyClass<5>&& data) : data((MyClass<5>&&)data) {}
GREATLY APPRECIATED!
Because
data
is not an rvalue. Rvalues are nameless.data
is a name ⇒ not an rvalue. Named rvalue references are references that bind to rvalues but they are not rvalues themselves.Your cast is correct but not generic and not idiomatic. The standard library offers
std::move
precisely for this purpose, use it.I would argue that it should be initialized in the initialisation list to the pointer to allocated data. Everything should be initialised in the initialisation list. If this is impossible then probably there's a problem with your design.
Of course in real code you should be using
std::vector
orstd::array
.The size is not defined dynamically. It must be known at compile time.