将一些对象传递给函数而不复制它们

时间:2015-04-02 16:40:33

标签: c++

考虑C拥有一些资源而无法复制。 在我的问题的以下简化示例中,将几个C对象传递给某个方法(hi_all)的最佳方法是什么?

我发现使用std::reference_wrapper的唯一解决方案。有没有更好的解决方案?

#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;
}

2 个答案:

答案 0 :(得分:2)

reference_wrapper的解决方案对我来说似乎已经足够了。请注意,如果你对它们感觉更好,你也可以使用指针向量(但我强烈坚持你的解决方案带参考更清晰,因为它更符合<逻辑正确)。

如果你仍想让它变得更简单/更好,我会看到两种方式。

首先,您可以将vanother_C作为单独的参数传递给您。快速,简单,但不是很可扩展(可能你不需要它吗?)。

其次,您可以创建一些通用包装器来生成引用向量,并在此代码中使用它们。

顺便说一句,如果你知道编译时的对象数量(不幸的话,似乎并非如此),你可以使用可变参数模板。

类似的方法可用于创建包装器:

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;
}

然后,代码中的某处:

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

答案 1 :(得分:1)

在这里,我将提供固定且更通用的@ lisyarus解决方案。它足够接近我想要的东西。也许有人会发现它很有用:

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;
}