Talk:cpp/language/move assignment
So I'll start from beginning (: On this page there is possible implementation of std::remove algorithm, which works incorrectly with T = std::vector<int> from libc++ and libstdc++. (works correctly with msvc)
Test, for prove:
#include <iostream> // std::cout #include <vector> #include <algorithm> namespace my { template<class ForwardIt, class T> ForwardIt remove( ForwardIt first, ForwardIt last, const T& value) { ForwardIt result = first; for (; first != last; ++first) { if (!(*first == value)) { *result = std::move(*first); ++result; } } return result; } } inline void fundamental_test() { std::cout << "fundamental test:" << std::endl; const int val_to_remove = 4; std::vector<int> int_vec; int_vec.push_back(1); int_vec.push_back(2); int_vec.push_back(3); std::cout << "size = " << int_vec.size() << std::endl; int_vec.erase( my::remove(int_vec.begin(), int_vec.end(), val_to_remove), // test int_vec.end() ); std::cout << "size = " << int_vec.size() << std::endl; for(const auto& i: int_vec) { std::cout << i << std::endl; } } inline void container_test() { std::cout << "stl container test" << std::endl; typedef std::vector<int> Element; typedef std::vector<Element> Container; Element val_to_remove; val_to_remove.push_back(1); val_to_remove.push_back(2); val_to_remove.push_back(3); val_to_remove.push_back(4); Element val_other; val_other.push_back(1); val_other.push_back(4); val_other.push_back(5); Container container; container.push_back(val_other); container.push_back(val_other); container.push_back(val_other); container.erase( my::remove(container.begin(), container.end(), val_to_remove), // test container.end() ); std::cout << "size = " << container.size() << std::endl; for (const auto& i: container) { if (i.empty()) { std::cout << "empty"; } else { for (const auto& j: i) { std::cout << j << " "; } } std::cout << std::endl; } } int main() { fundamental_test(); container_test(); return EXIT_SUCCESS; }
If you use std::remove from library:
fundamental test: size = 3 size = 3 1 2 3 stl container test size = 3 1 4 5 1 4 5 1 4 5
but if you use my::remove:
fundamental test: size = 3 size = 3 1 2 3 stl container test size = 3 empty empty empty
The problem is in line:
*result = std::move(*first); when result is equal to first it self-move-assigning => cleared.
What I'm trying to say (: ? If you want to write algorithm that works with all implementation of stl, you need to remember that self-move-assign clear you container. And important notes about this implementaion, that implementation is correct and fit c++ standard.
Environment: g++ 4.7 ubuntu, macos clang 5.0, msvc 2012 Ruslo 13:55, 25 August 2013 (PDT)
- Okay, I think I'm starting to understand. 17.6.4.9/1 of n3690 ("Function arguments") says "Each of the following applies to all arguments to functions defined in the C++ standard library...If a function argument binds to an rvalue reference parameter, the implementation may assume that this parameter is a unique reference to this argument."
- So that basically means that containers like std::vector don't need to check for self-assignment in their operator=, because they can assume that they'll never encounter self assignment.
- Does that sound right? If so, I wonder if this is something that would be useful to have on the various container operator= pages. (Although it would be kind of repetitive, which is an argument for just saying it once e.g. here.) --Nate 18:28, 25 August 2013 (PDT)
- I think any page you can refer to will be fine. But I can't image how to do it without std::move function (of course if you don't create your own). My point is, you just need to remember easy pattern: when you see 'x = std::move(y)' can you guarantee, that x is not y? Ruslo 20:56, 25 August 2013 (PDT)
- This looks like the "possible implementation" of std::remove_if that was posted on this wiki, which is simply invalid. I'll fix it. As for library self-moves, there aren't too many move assignment operators in the standard library, no harm mentioning in every container::operator= that self-move-assignment is not necessarily tested... on second thought, there are plenty more resource-owning classes in the library. --Cubbi 02:59, 26 August 2013 (PDT)
[edit] Move assignment operator taking arguments passed by value??
In the Copy-and-Swap idiom section. You provide example like this:
T& T::operator=(T arg) { swap(arg); return *this; }
This is hardly a move assignment operator; it's a copy assignment operator!