发送垃圾邮件 std::move 是正确的选择吗?
Spamming std::move is the way to go?
关于std::move
,根据http://en.cppreference.com/w/cpp/utility/move,这是我可以解释的:-
- 如果我想转让所有权,我必须调用
std::move
(或者在极少数情况下,std::forward
)。
std::move
的职责是打电话给 operator=(A&& other)
。
- 移动操作最重要的步骤应该在
operator=(A&&)
中实现。
- 确保调用
operator=(A&&)
很棘手。它需要一个特殊的转换器。
- 在 C++ 世界中只有 两个转换器可以将变量转换为
xvalue
(&&):std::move
和 std::forward
.
问题
在我的代码中添加了很多 std::move(std::unique_ptr)
之后,我开始担心像转让所有权这样的基本功能,我不得不严重依赖标准库 (std::
)。
我真的必须使用 std::move
来转移所有权吗?
代码库的许多地方的垃圾邮件和硬代码调用std::move
是否是获得高标准程序的正确方法?
要std::move
封装吗?
他们其实是一个问题,只是从不同的角度提问。
编辑
根据要求,这是我的试错。编译成功了。
我对代码没有问题,但我担心它的方法/模式。
https://ideone.com/y8Pcgf
class T{
public: int value;
public: T(int a=1234){
value = a;
}
};
int main() {
std::unique_ptr<T> t1 = std::unique_ptr<T>(new T(1));
void* databaseNew=operator new [](sizeof(std::unique_ptr<T>));
std::unique_ptr<T>* t1ptr=static_cast<std::unique_ptr<T>*>(databaseNew);
new (t1ptr) std::unique_ptr<T>(std::move(t1));
return 0;
}
您抱怨的明确 move
的需要实际上是故意的。在 unique_ptr
之前,STL 有一个叫做 auto_ptr
的可怕结构。它会隐含地移动所有权,并且几乎无法使用,除非你真的 真的 知道你在做什么。
为了使事情更有用,在大多数情况下,C++ 现在要求您通过使用 std::move
.
明确声明您打算将所有权转移到容器上
事实上,std::move
只不过是对右值引用的转换。
有些情况下不需要这样明确的说明。例如,如果您从中获得所有权的容器已经是一个右值(例如 - 一个临时对象),则不需要使用 std::move
的情况。例如,以下不会编译:
std::unique_ptr<int> a;
a = new int;
但是以下不需要移动就可以:
std::unique_ptr<int> a;
a = std::unique_ptr<int>(new int);
尽管调用了移动运算符,但不需要调用 std::move
的原因是我们将所有权移出的对象已经是一个临时对象(即 - 一个右值),所以不需要强制转换是必要的。
另一个例子是如果你调用一个 return 是 unique_ptr 的函数。您可能必须在函数内部调用 std::move
才能将其放入 return 值,但您无需在函数的 return 值上调用 std::move
即可将其放入外面 unique_ptr
。它已经是一个右值,因此不需要转换。
经验法则:
如果您处于推导的 x 值上下文中,请使用 std::forward
:
template<class T>
void foo(T&& t) // T is deduced x-value, so we forward it
{
bar(std::forward<T>(t));
}
否则使用std::move
template<class T>
void foo1(std::vector<T> v) // although vector<T> is deduced, it's not an x-value
{
bar(std::move(v)); // so move it
}
template<class T>
void foo2(std::vector<T>&& v) // although vector<T> is deduced, it's not an x-value.
// In this case an r-value reference
{
bar(std::move(v)); // so move it
}
template<class T>
void foo3(std::vector<T>& v) // although vector<T> is deduced, it's not an x-value.
// In this case an l-value reference
{
bar(std::move(v)); // so move it
}
void foo4(std::vector<int> v) // complete type
{
bar(std::move(v)); // so move it
}
void foo5(std::vector<int> const & v) // const reference
{
bar(v); // not much point in moving it. std::move would cast it
// to std::vector<int> const&&, which although is detectable
// decays to std::vector<int> const&
}
which although is detectable... what?
允许,如果不一定建议这样写代码:
#include <iostream>
struct X
{
void foo() const &
{
// do one thing...
std::cout << "one thing\n";
}
void foo() const &&
{
// do something else...
std::cout << "or another\n";
}
};
int main()
{
const X x;
x.foo();
std::move(x).foo();
}
const 右值引用确实存在,只是没有人使用它们,因为没有合理的用例。
关于std::move
,根据http://en.cppreference.com/w/cpp/utility/move,这是我可以解释的:-
- 如果我想转让所有权,我必须调用
std::move
(或者在极少数情况下,std::forward
)。 std::move
的职责是打电话给operator=(A&& other)
。- 移动操作最重要的步骤应该在
operator=(A&&)
中实现。 - 确保调用
operator=(A&&)
很棘手。它需要一个特殊的转换器。 - 在 C++ 世界中只有 两个转换器可以将变量转换为
xvalue
(&&):std::move
和std::forward
.
问题
在我的代码中添加了很多 std::move(std::unique_ptr)
之后,我开始担心像转让所有权这样的基本功能,我不得不严重依赖标准库 (std::
)。
我真的必须使用 std::move
来转移所有权吗?
代码库的许多地方的垃圾邮件和硬代码调用std::move
是否是获得高标准程序的正确方法?
要std::move
封装吗?
他们其实是一个问题,只是从不同的角度提问。
编辑
根据要求,这是我的试错。编译成功了。
我对代码没有问题,但我担心它的方法/模式。
https://ideone.com/y8Pcgf
class T{
public: int value;
public: T(int a=1234){
value = a;
}
};
int main() {
std::unique_ptr<T> t1 = std::unique_ptr<T>(new T(1));
void* databaseNew=operator new [](sizeof(std::unique_ptr<T>));
std::unique_ptr<T>* t1ptr=static_cast<std::unique_ptr<T>*>(databaseNew);
new (t1ptr) std::unique_ptr<T>(std::move(t1));
return 0;
}
您抱怨的明确 move
的需要实际上是故意的。在 unique_ptr
之前,STL 有一个叫做 auto_ptr
的可怕结构。它会隐含地移动所有权,并且几乎无法使用,除非你真的 真的 知道你在做什么。
为了使事情更有用,在大多数情况下,C++ 现在要求您通过使用 std::move
.
事实上,std::move
只不过是对右值引用的转换。
有些情况下不需要这样明确的说明。例如,如果您从中获得所有权的容器已经是一个右值(例如 - 一个临时对象),则不需要使用 std::move
的情况。例如,以下不会编译:
std::unique_ptr<int> a;
a = new int;
但是以下不需要移动就可以:
std::unique_ptr<int> a;
a = std::unique_ptr<int>(new int);
尽管调用了移动运算符,但不需要调用 std::move
的原因是我们将所有权移出的对象已经是一个临时对象(即 - 一个右值),所以不需要强制转换是必要的。
另一个例子是如果你调用一个 return 是 unique_ptr 的函数。您可能必须在函数内部调用 std::move
才能将其放入 return 值,但您无需在函数的 return 值上调用 std::move
即可将其放入外面 unique_ptr
。它已经是一个右值,因此不需要转换。
经验法则:
如果您处于推导的 x 值上下文中,请使用 std::forward
:
template<class T>
void foo(T&& t) // T is deduced x-value, so we forward it
{
bar(std::forward<T>(t));
}
否则使用std::move
template<class T>
void foo1(std::vector<T> v) // although vector<T> is deduced, it's not an x-value
{
bar(std::move(v)); // so move it
}
template<class T>
void foo2(std::vector<T>&& v) // although vector<T> is deduced, it's not an x-value.
// In this case an r-value reference
{
bar(std::move(v)); // so move it
}
template<class T>
void foo3(std::vector<T>& v) // although vector<T> is deduced, it's not an x-value.
// In this case an l-value reference
{
bar(std::move(v)); // so move it
}
void foo4(std::vector<int> v) // complete type
{
bar(std::move(v)); // so move it
}
void foo5(std::vector<int> const & v) // const reference
{
bar(v); // not much point in moving it. std::move would cast it
// to std::vector<int> const&&, which although is detectable
// decays to std::vector<int> const&
}
which although is detectable... what?
允许,如果不一定建议这样写代码:
#include <iostream>
struct X
{
void foo() const &
{
// do one thing...
std::cout << "one thing\n";
}
void foo() const &&
{
// do something else...
std::cout << "or another\n";
}
};
int main()
{
const X x;
x.foo();
std::move(x).foo();
}
const 右值引用确实存在,只是没有人使用它们,因为没有合理的用例。