Moving a shared_ptr will set the moved shared_ptr to nullptr so why it is allowed to do this in a const_iterator ?
std::vector<std::shared_ptr<std::string>> sharedPtrVector;
sharedPtrVector.push_back(std::shared_ptr<std::string>(new std::string("test")));
for (std::vector<std::shared_ptr<std::string>>::const_iterator it = sharedPtrVector.begin(); it != sharedPtrVector.end(); ++it) {
// Not allowed if const_iterator
//*it = nullptr;
// Not allowed if const_iterator
//*static_cast<std::shared_ptr<std::string> *>(&*it) = nullptr;
// Allowed even if const_iterator
std::shared_ptr<std::string> test(std::move(*it));
}
sharedPtrVector is in an undefined state after that.
As discussed in the comments, std::move
doesn't actually perform the move, it simply casts the iterator to an rvalue-reference so it is ready to be moved from. In the case of const std::shared_ptr<T>&
it will cast to a const std::shared_Ptr<T>&&
which is not accepted by the std::shared_ptr<T>
move constructor so it will use the copy constructor instead.
This can be confirmed by checking if the shared_ptr<T>
pointed to by the const_iterator
is empty afterwards:
std::vector<std::shared_ptr<std::string>> sharedPtrVector;
sharedPtrVector.emplace_back(std::make_shared<std::string>("test"));
for (auto it = sharedPtrVector.cbegin(); it != sharedPtrVector.cend(); ++it) {
std::shared_ptr<std::string> test(std::move(*it));
if (*it)
std::cout << "*it is not empty\n";
}