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!