C ++ 03通过构造函数将一个向量移动到一个类成员中(移动语义)

时间:2014-08-26 14:06:43

标签: c++ vector move-semantics c++03

我只能访问C ++ 03,我经常想要将一个向量移动到一个函数中,就像在C ++ 11中一样。如何做的问题不要过多地混淆代码的用户。所以我的问题是程序员在C ++ 11之前是如何做到的。

我知道可以使用交换功能“移动”向量。所以这就是我提出的:

class Foo
{
public:
    Foo(std::vector<int>& vec)
    {
        using std::swap;
        swap(vec, m_vec);   // "move" vec into member vector
    }

private:
    std::vector<int> m_vec;
};

// usage:
std::vector<int> v(100, 1337);
Foo foo(v);
// v.empty() == true

这种方法的问题在于,用户不明白他们的矢量将被移动到类Foo中。有这种问题的最佳实践解决方案吗?提前谢谢!

5 个答案:

答案 0 :(得分:5)

您可以使用一些带有显式名称的包装器:

template <typename T>
class MyMove
{
public:
    explicit MyMove(T& t) : t(t) {}

    T& get() {return t;}
private:
    T& t;
};

template <typename T>
MyMove<T> myMove(T& t) { return MyMove<T>(t); }

然后

class Foo
{
public:
    Foo(MyMove<std::vector<int>> vec)
    {
        using std::swap;
        swap(vec.get(), m_vec);   // "move" vec into member vector
    }

private:
    std::vector<int> m_vec;
};

用法:

std::vector<int> v(100, 1337);
Foo foo(myMove(v));

答案 1 :(得分:5)

您可以定义包装引用的类型和包装它的函数,以提供类似于在调用站点移动语义的类型。

的内容
template <typename T> struct move_ref {
    explicit move_ref(T & ref) : ref(ref) {}
    T & ref;
};

template <typename T> move_ref<T> move(T & t) {return move_ref<T>(t);}

Foo(move_ref< std::vector<int> > vec)
{
    using std::swap;
    swap(vec.ref, m_vec);   // "move" vec into member vector
}

Foo foo(move(v));

或者,Boost有library允许移动语义而不使用C ++ 11。

答案 2 :(得分:3)

当然可以在 C ++ 03 移动语义

使用Boost.Move

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

class Foo
{
public:
    Foo(BOOST_RV_REF(std::vector<int>) vec)
    {
        std::swap(vec, m_vec);   // "move" vec into member vector
    }

private:
    std::vector<int> m_vec;
};

int main()
{
    std::vector<int> v(100, 1337);
    Foo foo(boost::move(v));
}

或者你可以自己编写 ,可以使用 l-values temporaries ,以及r_value_ref<T>包装器由于T&

,可以用作const T&operator T&()
#include <vector>
#include <utility>

template <typename T>
class r_value_ref
{
public:
    explicit r_value_ref(const T& t) : t(t) {}

    T& get() const
    {
        return const_cast<T&>(t);
    }

    operator T&() const
    {
        return const_cast<T&>(t);
    }

private:    
    const T& t;
};

template <typename T>
r_value_ref<T> my_move(const T& t)
{
    return r_value_ref<T>(t);
}

class Foo
{
public:
    Foo(r_value_ref<std::vector<int> > vec)
    {
        m_vec.swap(vec); // no .get() required !
        // or std::swap(vec.get(), m_vec);
    }

private:
    std::vector<int> m_vec;
};

int main()
{
    Foo foo_from_r_value(my_move(std::vector<int>(100, 1337)));

    std::vector<int> v2(100, 1337);
    Foo foo_from_l_value(my_move(v2));
}

Live demo link

但是,它不安全,例如r_value_ref<int> i(123); i.get() = 456;成功编译,但会导致未定义的行为。手写的r值参考包装需要更多努力才能使它们完全安全。

答案 3 :(得分:1)

如果我说得对,你想通过构造函数调用“移动”类成员中的向量。

在C ++ 11中,您必须提供带std::vector<T>&&参数的构造函数并调用

Foo my_foo(std::move(my_vector));

在C ++ 03中,您可以添加“命名构造函数”或为您完成此任务的朋友。

template <class T>
class Foo
{
public:

  static Foo<T> move_from_vector(std::vector<T> & vector)
  {
    Foo<T> new_foo;
    new_foo.m_vec.swap(vector);
    return new_foo;
  }
private:
  std::vector<T> m_vec;
};

你可以像这样使用它:

int main()
{
    std::vector<int> h(5);
    Foo<int> g(Foo<int>::move_from_vector(h));
}

通过这种方式很明显,向量被移动了,移动语法与C ++ 11没有太大差别(当然,这是非泛型的)。

请注意,如果关闭优化,则会复制Foo

答案 4 :(得分:0)

C ++ 03方法是使用std :: auto_ptr来表示数据的传递所有权

class Foo
{
public:
    explicit Foo(std::auto_ptr<std::vector<int> > vec)
       : m_vec(vec)
    {
    }

private:
    Foo(const Foo&);
    Foo& operator=(const Foo&);

    std::auto_ptr<std::vector<int> > m_vec;
};

// usage:
std::auto_ptr<std::vector<int> > v(new std::vector<int>(100, 1337));
Foo foo(v);

// v.get() == 0
签名中的std :: auto_ptr清楚地表明数据是在函数内部传递的,由于复制auto_ptr的性质而使调用站点留空指针。

请注意,需要禁止或明确定义正确的复制构造和此类的赋值,因为默认的复制构造函数和auto_ptr的赋值通常不是正确的。