user3689849
user3689849

Reputation: 521

move the data into std::make_pair with boost::move

I am using:

This works for me:

std::pair<std::vector<std::string>, int> move_pair()
{
    std::vector<std::string> temp;
    //do some jobs
    return std::make_pair(std::move(temp), 0);
}

But this one does not work (can not use boost::move to move temp):

std::pair<boost::container::vector<std::string>, int> move_pair()
{
    boost::container::vector<std::string> temp;
    //do some jobs
    
    return std::make_pair(boost::move(temp), 0);
}

Is there any way to move the temp of boost::container with std::pair from a c++98/03 compiler?

Is there a boost::container::pair or boost::container::make_pair I should use?

Error message:

..\networkLibTest\main.cpp(18) : error C2248: 'boost::rv<T>::rv' : cannot access private member declared in class 'boost::rv<T>'
        with
        [
            T=boost::container::vector<std::string>
        ]
        g:\Tools\3rdLibs\boost\boost_1_55_0\boost/move/core.hpp(71) : see declaration of 'boost::rv<T>::rv'
        with
        [
            T=boost::container::vector<std::string>
        ]
..\networkLibTest\main.cpp(18) : error C2248: 'boost::rv<T>::~rv' : cannot access private member declared in class 'boost::rv<T>'
        with
        [
            T=boost::container::vector<std::string>
        ]
        g:\Tools\3rdLibs\boost\boost_1_55_0\boost/move/core.hpp(70) : see declaration of 'boost::rv<T>::~rv'
        with
        [
            T=boost::container::vector<std::string>
        ]

Upvotes: 1

Views: 1233

Answers (2)

user3689849
user3689849

Reputation: 521

I just come up a naive pair and make_pair, do not know there are any pitfall hidden by this implementation or not

pair.hpp

namespace wlg{

template<typename T1, typename T2>
class pair
{
public:
    typedef T1 first_type;
    typedef T2 second_type;

    pair(T1 const &fir, T2 const &sec);
    pair(BOOST_RV_REF(T1) fir, T2 const &sec);
    pair(T1 const &first, BOOST_RV_REF(T2) sec);
    pair(BOOST_RV_REF(T1) fir, BOOST_RV_REF(T2) sec) :
        first(boost::move(fir)),
        second(boost::move(sec))
    {
#ifdef WLG_PAIR_DEBUG_ENABLE
        std::cout<<"pair(BOOST_RV_REF(T1) first, BOOST_RV_REF(T2) second)"<<std::endl;
#endif
    }

    pair(pair const &data);
    pair(BOOST_RV_REF(pair) data)            //Move constructor
        : first(boost::move(data.first)),
          second(boost::move(data.second))
    {
#ifdef WLG_PAIR_DEBUG_ENABLE
        std::cout<<"pair(BOOST_RV_REF(pair) data)"<<std::endl;
#endif
    }

    pair& operator=(BOOST_COPY_ASSIGN_REF(pair) data);

    pair& operator=(BOOST_RV_REF(pair) data) //Move assignment
    {
#ifdef WLG_PAIR_DEBUG_ENABLE
        std::cout<<"operator=(BOOST_RV_REF(pair) data)"<<std::endl;
#endif
        if (this != &data){
            first = boost::move(data.first);
            second = boost::move(data.second);
        }
        return *this;
    }

    void swap(pair &data)
    {
        swap(data.first, first);
        swap(data.second, second);
    }

private:
    template<class T>
    void swap(T &fir, T &sec)
    {
        T tmp(::boost::move(fir));
        fir = ::boost::move(sec);
        sec = ::boost::move(tmp);
    }

public:
    T1 first;
    T2 second;

private:
    BOOST_COPYABLE_AND_MOVABLE(pair)
};

template<typename T1, typename T2>
pair<T1, T2>::pair(const T1 &fir, const T2 &sec) :
    first(fir),
    second(sec)
{
#ifdef WLG_PAIR_DEBUG_ENABLE
    std::cout<<"pair(const T1 &first, const T2 &second)"<<std::endl;
#endif
}

template<typename T1, typename T2>
pair<T1, T2>::pair(BOOST_RV_REF(T1) fir, const T2 &sec) :
    first(boost::move(fir)),
    second(sec)
{
#ifdef WLG_PAIR_DEBUG_ENABLE
    std::cout<<"pair(BOOST_RV_REF(T1) first, const T2 &second)"<<std::endl;
#endif
}

template<typename T1, typename T2>
pair<T1, T2>::pair(const T1 &fir, BOOST_RV_REF(T2) sec) :
    first(fir),
    second(boost::move(sec))
{
#ifdef WLG_PAIR_DEBUG_ENABLE
    std::cout<<"pair(const T1 &first, BOOST_RV_REF(T2) second)"<<std::endl;
#endif
}

template<typename T1, typename T2>
pair<T1, T2>::pair(const pair &data) :
    first(data.first),
    second(data.second)
{
#ifdef WLG_PAIR_DEBUG_ENABLE
    std::cout<<"pair(const pair &data)"<<std::endl;
#endif
}

template<typename T1, typename T2>
inline
pair<T1, T2> make_pair(T1 const &fir, T2 const &sec)
{
#ifdef WLG_PAIR_DEBUG_ENABLE
    std::cout<<"make_pair(T1 const &first, T2 const &second)"<<std::endl;
#endif
    return pair<T1, T2>(fir, sec);
}

template<typename T1, typename T2>
inline
pair<T1, T2> make_pair(BOOST_RV_REF(T1) fir, T2 const &sec)
{
#ifdef WLG_PAIR_DEBUG_ENABLE
    std::cout<<"make_pair(BOOST_RV_REF(T1) first, T2 const &second)"<<std::endl;
#endif
    return pair<T1, T2>(boost::move(fir), sec);
}

template<typename T1, typename T2>
inline
pair<T1, T2> make_pair(T1 const &fir, BOOST_RV_REF(T2) sec)
{
#ifdef WLG_PAIR_DEBUG_ENABLE
    std::cout<<"make_pair(T1 const &first, BOOST_RV_REF(T2) second)"<<std::endl;
#endif
    return pair<T1, T2>(fir, boost::move(sec));
}

template<typename T1, typename T2>
inline
pair<T1, T2> make_pair(BOOST_RV_REF(T1) fir, BOOST_RV_REF(T2) sec)
{
#ifdef WLG_PAIR_DEBUG_ENABLE
    std::cout<<"make_pair(BOOST_RV_REF(T1) first, BOOST_RV_REF(T2) second)"<<std::endl;
#endif
    return pair<T1, T2>(boost::move(fir), boost::move(sec));
}

template<typename T1, typename T2>
inline
bool operator==(pair<T1, T2> const &fir, pair<T1, T2> const &sec)
{
    return fir.first == sec.first && fir.second == sec.second;
}

template<typename T1, typename T2>
inline
bool operator!=(pair<T1, T2> const &fir, pair<T1, T2> const &sec)
{
    return !(fir == sec);
}

template<typename T1, typename T2>
inline
bool operator>=(pair<T1, T2> const &fir, pair<T1, T2> const &sec)
{
    return fir.first >= sec.first && fir.second >= sec.second;
}

template<typename T1, typename T2>
inline
bool operator<=(pair<T1, T2> const &fir, pair<T1, T2> const &sec)
{
    return !(fir >= sec);
}

template<typename T1, typename T2>
inline
bool operator>(pair<T1, T2> const &fir, pair<T1, T2> const &sec)
{
    return fir.first > sec.first && fir.second > sec.second;
}

template<typename T1, typename T2>
inline
bool operator<(pair<T1, T2> const &fir, pair<T1, T2> const &sec)
{
    return !(fir > sec);
}

}

Test codes

#define WLG_PAIR_DEBUG_ENABLE

#include "pair.h"

#include <boost/container/vector.hpp>
#include <boost/move/move.hpp>

#include <string>

Type make_pair_00()
{
    boost::container::vector<std::string> temp_1;
    boost::container::vector<std::string> temp_2;

    return wlg::make_pair(temp_1, temp_2);
}

Type make_pair_01()
{
    boost::container::vector<std::string> temp_1;
    boost::container::vector<std::string> temp_2;

    return wlg::make_pair(boost::move(temp_1), temp_2);
}

Type make_pair_02()
{
    boost::container::vector<std::string> temp_1;
    boost::container::vector<std::string> temp_2;

    return wlg::make_pair(temp_1, boost::move(temp_2));
}

Type make_pair_03()
{
    boost::container::vector<std::string> temp_1;
    boost::container::vector<std::string> temp_2;

    return wlg::make_pair(boost::move(temp_1), boost::move(temp_2));
}

int main()
{        
    Type target_00 = make_pair_00();
    std::cout<<std::endl;

    Type target_01 = make_pair_01();
    std::cout<<std::endl;

    Type target_02 = make_pair_02();
    std::cout<<std::endl;

    Type target_03 = make_pair_03();
    std::cout<<std::endl;

    Type target_04 = boost::move(target_00);
    std::cout<<std::endl;

    target_00 = make_pair_00();
    std::cout<<std::endl;
}

The results

make_pair(T1 const &first, T2 const &second)
pair(const T1 &first, const T2 &second)

make_pair(BOOST_RV_REF(T1) first, T2 const &second)
pair(BOOST_RV_REF(T1) first, const T2 &second)

make_pair(T1 const &first, BOOST_RV_REF(T2) second)
pair(const T1 &first, BOOST_RV_REF(T2) second)

make_pair(BOOST_RV_REF(T1) first, BOOST_RV_REF(T2) second)
pair(BOOST_RV_REF(T1) first, BOOST_RV_REF(T2) second)

pair(BOOST_RV_REF(pair) data)

make_pair(T1 const &first, T2 const &second)
pair(const T1 &first, const T2 &second)
operator=(BOOST_RV_REF(pair) data)

target_00~target_03 do not call any copy constructor, maybe it is optimize by RVO?

Upvotes: 0

T.C.
T.C.

Reputation: 137425

boost::move emulates move semantics in C++98 mode by essentially casting the type of the provided reference into a different "wrapped" type that says "hey, I'm an rvalue, steal from me!".

However, for this to work, the type's constructors/assignment operators must be able to recognize this "wrapped" type and act accordingly, which means that this requires cooperation from the type.

std::vector obviously knows nothing about boost, and the boost::move implementation for non-cooperating types simply returns what is passed to it, so your code with std::vector compiles, but actually copies rather than moves.

Although boost::container::vector is a cooperating type, the wrapped type used by the move semantics emulation is not constructible, copyable, or even destructible - the reference returned by boost::move is obtained via a static_cast on the reference passed in. Thus, you can't use C++03 make_pair with the return value of boost::move because C++03 make_pair takes its parameters by value, which would attempt to make a copy of the wrapped type, and fail hard. If you use boost::move, the best you can do is calling std::pair's constructor directly:

return std::pair<boost::container::vector<std::string>, int>(boost::move(temp), 0);

which moves temp into a temporary boost::container::vector<std::string> and pass that temporary to std::pair's constructor, but since std::pair's constructor takes its arguments by const reference and not by value, and hence will make a copy anyway, there is no point in doing this.

Upvotes: 3

Related Questions