Tech Off Thread

5 posts

Forum Read Only

This forum has been made read only by the site admins. No new threads or comments can be added.

A moving question

Back to Forum: Tech Off
  • User profile image
    Norville​Shaggy

    Why can't container::value_type invoke a move like make_pair can ?

    I'm using Visual Studio 2012

    Code example

    #include <iostream>
    #include <unordered_map>
    #include <utility> // move, make_pair
    #include <algorithm> // swap
    
    struct move_me {
        typedef move_me class_type;
        int *ptr_value;
        int moved;
        int copied;
    
        move_me() : ptr_value(nullptr), moved(), copied() {}
        explicit move_me(const int val) : ptr_value(new int(val)), moved(), copied() {
        }
        ~move_me() {
            if (ptr_value) {
                delete ptr_value;
            }
        }
    
        // Copy
        move_me(const move_me &other) :
            moved(other.moved), copied(other.copied + 1) {
                if (other.ptr_value) {
                    ptr_value = new int(*other.ptr_value);
                } else {
                    ptr_value = nullptr;
                }
        }
        move_me &operator=(const move_me &other) {
            move_me(other).swap(*this);
            return *this;
        }
    
        // Move
        move_me(move_me &&other) {
            ptr_value = other.ptr_value;
            other.ptr_value = nullptr;
            moved = other.moved + 1;
            copied = other.copied;
        }
        move_me &operator=(move_me &&other) {
            move_me(std::move(other)).swap(*this);
            return *this;
        }
    
        void print() const {
            using namespace std;
            if (ptr_value)
                cout << "ptr_value: " << *ptr_value << endl;
            else
                cout << "ptr_value: <nullptr>" << endl;
            cout << "moved: " << moved << endl;
            cout << "copied: " << copied << endl;
        }
        void swap(move_me& other) {
            std::swap(ptr_value, other.ptr_value);
            std::swap(moved, other.moved);
            std::swap(copied, other.copied);
        }
    
        size_t hash() const {
            return std::hash<int>()(*ptr_value);
        }
        bool operator==(const class_type& other) const { return *ptr_value == *other.ptr_value; }
        bool operator< (const class_type& other) const { return *ptr_value < *other.ptr_value; }
        bool operator<=(const class_type& other) const { return *ptr_value <= *other.ptr_value; }
    };
    
    struct hash_move_me {
        size_t operator()(const move_me& key_val) const {
            return key_val.hash();
        }
    };
    
    int main()
    {
        using namespace std;
    
        typedef unordered_map<move_me, size_t, hash_move_me> m_type;
        m_type m;
    
        auto find_and_prt = [&](const int val) {
            m.find(move_me(val))->first.print();
            cout << endl;
        };
    
        // Normal way
        // Expect only moves
        m.insert(m_type::value_type(move_me(111), 123));
        find_and_prt(111);
    
        // Lets make it very clear for the compiler that we want a move here
        m.insert(move(m_type::value_type(move(move_me(222)), 123)));
        find_and_prt(222);
    
        // We're in luck, special case, standard container
        m.insert(make_pair(move_me(333), 123));
        find_and_prt(333);
    
        cout << "done" << endl << endl;
        return 0;
    }

  • User profile image
    Norville​Shaggy

    This function use forward:

    Should it not use move instead?

    I used forward in one of my classes, that also caused a copy so i switch to move which did the desired action.

    Can somebody explain why the code doesn't do the right thing?


        template<class _Other1,
            class _Other2>
            pair(pair<_Other1, _Other2>&& _Right,
                typename enable_if<is_convertible<_Other1, _Ty1>::value
                    && is_convertible<_Other2, _Ty2>::value,
                    void>::type ** = 0)
            : first(_STD forward<_Other1>(_Right.first)),
                second(_STD forward<_Other2>(_Right.second))
            {    // construct from moved compatible pair
            }
    
    

  • User profile image
    STL

    > Why can't container::value_type invoke a move like make_pair can ?

    make_pair(k, v) returns pair<K, V>.

    map<K, V>::value_type is pair<const K, V>.

    Modifiable rvalues can be moved from, but const rvalues must be copied from.

    > Should it not use move instead?

    What it's doing is correct and required by the Standard. move() here would be incorrect (the reason is that the pair's element types might be references - it is VERY subtle).

    You should try to avoid looking at the Standard Library's implementation too much. It's full of complicated stuff (that we almost never explain with comments; we'd like to someday, but for now we're way too busy), and doesn't always demonstrate proper style. For example, in other places we say "forward" when it's identical to "move" but we really should be saying "move". (One of the items on my todo list is to clean that up.)

    The rules for users to follow are simple: when moving, say move(). When perfect forwarding, say forward<T>(t). Never confuse the two.

  • User profile image
    shahidsaif

    Why showing the error in this code. Anyone can let me know.

  • User profile image
    Ion Todirel

    , shahidsaif wrote

    Why showing the error in this code. Anyone can let me know.

    what compiler or version of Visual Studio do you use?

Conversation locked

This conversation has been locked by the site admins. No new comments can be made.