I have been playing around with std::vector to understand when objects are constructed, destructed, copy constructed and move constructed. To so do, I have written the following program
#include <iostream>
#include <vector>
class Test {
public:
Test() {
std::cout << "Constructor called for " << this << std::endl;
}
Test(const Test& x) {
std::cout << "Copy Constructor called for " << this << std::endl;
}
Test(Test&& x) {
std::cout << "Move Constructor called for " << this << std::endl;
}
~Test() {
std::cout << "Destructor called for " << this << std::endl;
}
};
int main() {
std::vector<Test> a( 1 );
a.resize(3);
return 0;
}
When a is resized, reallocation happens. My guess would have been that the object a[0] is moved constructed to the new a[0]. But, with libc++ and libstdc++, it seems that the copy constructor is called and not the move constructor. Is there any reason for such a behaviour?
vector::resize() The function alters the container's content in actual by inserting or deleting the elements from it. It happens so, If the given value of n is less than the size at present then extra elements are demolished.
std::move is actually just a request to move and if the type of the object has not a move constructor/assign-operator defined or generated the move operation will fall back to a copy.
This code demonstrates that emplace_back calls the copy constructor of A for some reason to copy the first element. But if you leave copy constructor as deleted, it will use move constructor instead.
The C++ function std::vector::resize() changes the size of vector. If n is smaller than current size then extra elements are destroyed. If n is greater than current container size then new elements are inserted at the end of vector. If val is specified then new elements are initialed with val.
I just found the answer to the question. The move constructor has to be declared noexcept to do so. When such a change has been done
Test(Test&& x) noexcept {
std::cout << "Move Constructor called for " << this << std::endl;
}
the move constructor is called.
Just as @InsideLoop's answer said, the move constructor has to be declared "noexcept" to be called.
It is because in the vector::resize() function call stack, we can find move_if_noexcept() is called in function __construct_backward().(see [your library path]/include/c++/v1/memory line:1531)
construct(__a, _VSTD::__to_raw_pointer(__end2-1), _VSTD::move_if_noexcept(*--__end1));
According to the C++11 standard, we know that move constructor is used for temporary right value in normal. So the move constructor throwing exception is such a dangerous thing, and we can declare "noexcept" for the move constructor to avoid it.
Using move_if_noexcept(), although it loss in performance, but can make the process safe. And the function will activate the move constructor when move constructor is declared "noexcept".
(Sorry for my poor English.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With