Namespaces
Variants
Views
Actions

Talk:cpp/language/move operator

From cppreference.com

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)