简体   繁体   中英

Pass to a function several objects without copying them

Consider C holds some resource and cannot be copyable. What the best way to pass several C objects to some method ( hi_all in an following simplified example of my problem)?

The only solution I found it to use std::reference_wrapper . Is there any better solution?

#include <iostream>
#include <vector>
#include <memory>

class C
{
public:
    C(int i)      throw() : i(i),   isCopy(false)    { }
    //C(const C& c) = delete; //actual version
    C(const C& c) throw() : i(c.i), isCopy(true)     { }
    C(C&& c)      throw() : i(c.i), isCopy(c.isCopy) { }    

    void hi() const
    {
        std::cout<<"hi:\t"<<i<<", copy:\t"<<isCopy<<std::endl;
    }

public:
    int i;
    bool isCopy;
};

void hi_all(const std::vector<C>& v)
{
    std::cout<<"copies"<<std::endl;
    for(auto &c : v)
        c.hi();
}

void hi_all(const std::vector<std::reference_wrapper<C>>& v)
{
    std::cout<<"ref wrappers"<<std::endl;
    for(auto &c : v)
        c.get().hi();
}

void hi_all(const std::vector<C>& v, std::function<bool (const C&)> predicate)
{
    std::cout<<"predicate"<<std::endl;
    for(auto &c : v)
    {
        if(predicate(c))
            c.hi();
    }
}

int main()
{
    //one external source of objects
    std::vector<C> v;
    v.push_back(C(1));
    v.push_back(C(2));
    v.push_back(C(3));

    //another source of objects. just one instance for simplicity
    C another_c(4);

    std::vector<C> v2;
    std::vector<std::reference_wrapper<C>> v2_ref;

    for(auto &c : v)
    {
        if(c.i > 1)
        {
            v2.push_back(c); //fail: copy ctor
            v2_ref.push_back(std::reference_wrapper<C>(c));
        }
    }

    v2.push_back(another_c); //fail: copy ctor
    v2_ref.push_back(std::reference_wrapper<C>(another_c));

    hi_all(v2);
    hi_all(v2_ref);
    hi_all(v, [](const C& c){ return c.i > 1; }); //fail: another_c lost.

    return 0;
}

Your solution with reference_wrapper seems good enough to me. Note that you could also use a vector of pointers, if you feel better with them (but I strongly insist that your solution with references is more clear, as it is far more logically correct ).

If you still want to make it simpler/better, I see two ways.

Firstly, you can just pass v and another_C to you function as separate arguments. Fast, simple, but not very scalable (probably you don't need it here?).

Secondly, you can create some generic wrappers that will generate vectors of references, and use them in this code.

By the way, if you know the number of objects at compile-time (which, unfortunatelly, seems not to be the case), you could use variadic templates.

Similar approach can be used to create wrappers:

template <typename T>
using refs_vector_t = std::vector<std::reference_wrapper<T>>;

template <typename T>
void refs_vector_impl (refs_vector_t<T> & result) { }

template <typename ... Ts>
void refs_vector_impl (refs_vector_t<T> & result, T const & x, Ts const & ... ts)
{
    result.push_back(std::reference_wrapper<T>(x));
    refs_vector_impl(result, ts...);
}

// assuming Con is a container of T
template <typename Con, typename ... Ts>
void refs_vector_impl (refs_vector_t<T> & result, Con const & con, Ts const & ... ts)
{
    for (auto const & x : con)
        refs_vector_impl(result, x);
    refs_vector_impl(result, ts...);
}

template <typename T, typename ... Ts>
refs_vector_t<T> refs_vector (Ts const & ... ts)
{
    refs_vector_t<T> result;
    refs_vector_impl(result, ts...);
    return result;
}

Then, somewhere in your code:

hi_all(refs_vector<C>(v, another_C));

Here I'll place fixed and more generalized @lisyarus's solution. It's close enough to what I wanted. Maybe someone will find it useful:

template <typename T>
using refs_vector = std::vector < std::reference_wrapper<T> >;

template <typename T>
static void refs_vector_impl(refs_vector<T> & result) { }

template <typename T, typename ... Ts>
static void refs_vector_impl(refs_vector<T> & result, T & x, Ts & ... ts)
{
    result.push_back(std::reference_wrapper<T>(x));
    refs_vector_impl(result, ts...);
}

// assuming Con is a container of T
template <typename T, typename Con, typename ... Ts>
static void refs_vector_impl(refs_vector<T> & result, Con & con, Ts & ... ts)
{
    for (auto & x : con)
        refs_vector_impl(result, x);
    refs_vector_impl(result, ts...);
}

/* non constant references */
template <typename T, typename ... Ts>
refs_vector<T> refs(Ts& ... ts)
{
    refs_vector<T> result;
    refs_vector_impl(result, ts...);
    return result;
}

/* constant references */
template <typename T, typename ... Ts>
refs_vector<T const> crefs(Ts const & ... ts)
{
    refs_vector<T const> result;
    refs_vector_impl(result, ts...);
    return result;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM