I wanted to know what exactly happens internally when we call std::move on an object. For example:
class Holder {
int* m_ptr;
int m_size;
public:
Holder(int size) : m_size(size),
m_ptr(size ? new int[size] : 0) {
cout << "Constructor\n";
}
~Holder() {
cout << "Destructor\n";
delete[] m_ptr;
}
Holder(const Holder& other) {
cout << "Copy Constructor\n";
m_ptr = new int[other.m_size];
std::copy(other.m_ptr, other.m_ptr other.m_size, m_ptr);
m_size = other.m_size;
}
void swap(Holder& other) noexcept {
std::swap(this->m_ptr, other.m_ptr);
std::swap(this->m_size, other.m_size);
}
Holder& operator=(const Holder& other) {
cout << "Copy Assignment\n";
Holder(other).swap(*this);
}
Holder(Holder&& other) : m_ptr(other.m_ptr), m_size(other.m_size) {
cout << "Move Constructor\n";
other.m_ptr = nullptr;
other.m_size = 0;
}
Holder& operator=(Holder&& that) noexcept {
cout << "Move Assignment\n";
Holder(std::move(that)).swap(*this);
return *this;
}
};
Holder createHolder(int size) {
return Holder(size);
}
int main(void) {
Holder h = createHolder(1000);
return 0;
}
Gives the output as when compiled with '-fno-elide-constructors
':
Constructor
Move Constructor
Destructor
Move Constructor
Destructor
Destructor
Since we are returning from a function createHolder
and the return object is on the stack, how does the main
function still receives it? Not getting exactly what happens internally in memory.
Thanks.
CodePudding user response:
std::move
is a noop function that converts any kind of reference into an rvalue reference. So it doesn't actually "do" anything, it just changes how it's argument is used.
template <class T> constexpr remove_reference_t<T>&& move(T&& t) noexcept;
Returns: static_cast<remove_reference_t<T>&&>(t).
CodePudding user response:
std::move make your operator =, constructor is call correctly with what you defined in the Holder class
Holder(Holder&& other) : m_ptr(other.m_ptr), m_size(other.m_size) {
cout << "Move Constructor\n";
other.m_ptr = nullptr;
other.m_size = 0;
}
Holder& operator=(Holder&& that) noexcept {
cout << "Move Assignment\n";
Holder(std::move(that)).swap(*this);
return *this;
}
Since we are returning from a function createHolder and the return object is on the stack, how does the main function still receives it?
because your move constructor
you already copy pointer m_ptr(other.m_ptr) m_size(other.m_size) from Holder(size) -> move to Holder object in return register on stack -> move to Holder h in main function
Constructor -> of Holder(size);
Move Constructor -> Holder(size) move to Holder object in return register on stack
Destructor -> destructor of Holder(size)
Move Constructor -> from Holder object on stack -> Holder h in main
Destructor -> destructor of Holder object in return register
Destructor -> destructor of Holder h in main