我只能访问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中。有这种问题的最佳实践解决方案吗?提前谢谢!
答案 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));
}
但是,它不安全,例如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的赋值通常不是正确的。