复制 vs std::move 用于整数
copy vs std::move for ints
- 默认副本和该示例中的 std::move 有什么区别?
move
后对象是否有新旧依赖关系?
int main () {
int a = 100;
std::cout<<&a<<std::endl;
auto a_copy = a; // deduced as int
std::cout<<&a_copy<<std::endl;
auto a_move = std::move(a); // deduced as int
std::cout<<&a_move<<std::endl;
};
输出:
0x7fffffffe094
0x7fffffffe098
0x7fffffffe09c
What's difference between default copy and std::move in that example?
没有区别。复制一些东西满足移动的要求,并且在内置类型的情况下,移动被实现为一个副本。
After move the object is there any dependence between new and old
不,没有依赖关系。两个变量都是独立的。
在这个例子中,没有区别。我们最终会得到 3 个 int
的值为 100。当然,不同的类型肯定会有差异。例如,让我们考虑类似 vector<int>
:
std::vector<int> a = {1, 2, 3, 4, 5}; // a has size 5
auto a_copy = a; // copy a. now we have two vectors of size 5
auto a_move = std::move(a); // *move* a into a_move
最后一个变量 a_move
拥有 a
的内部指针。所以我们最终得到的是 a_move
是一个大小为 5 的向量,但是 a
现在是空的。 move
比 copy
更有效(想象一下,如果它是 1000 个字符串的向量 - a_copy
将涉及分配 1000 个字符串的缓冲区并复制 1000 个字符串,但是 a_move
只是分配了几个指针)。
对于其他一些类型,一个可能无效:
std::unique_ptr<int> a{new int 42};
auto a_copy = a; // error
auto a_move = std::move(a); // OK, now a_move owns 42, but a points to nothing
对于许多类型,虽然没有区别:
std::array<int, 100> a;
auto a_copy = a; // copy 100 ints
auto a_move = std::move(a); // also copy 100 ints, no special move ctor
更一般地说:
T a;
auto a_copy = a; // calls T(const T& ), the copy constructor
auto a_move = std::move(a); // calls T(T&& ), the move constructor
使用 std::move
只是将左值更改为亡值,因此它可以与移动构造函数和移动赋值运算符一起使用。这些对于内置类型不存在,因此在此示例中使用 move 没有区别。
为了扩展其他发帖者的答案,移动即复制范式适用于所有由 POD 类型组成(或由 POD 类型组成的其他类型组成)的数据结构,如本例所示:
struct Foo
{
int values[100];
bool flagA;
bool flagB;
};
struct Bar
{
Foo foo1;
Foo foo2;
};
int main()
{
Foo f;
Foo fCopy = std::move(f);
Bar b;
Bar bCopy = std::move(b);
return 0;
}
在 Foo
和 Bar
的情况下,没有有意义的方法将数据从一个移动到另一个,因为它们最终都是 POD 类型的聚合 - none 它们的数据是间接拥有的(指向或引用其他内存)。因此,在这些情况下,移动是作为副本实现的,而原件(f
、b
)在 std::move()
行上的分配后保持不变。
只有使用动态分配的内存或独特的资源才能有意义地实现移动语义。
- 默认副本和该示例中的 std::move 有什么区别?
move
后对象是否有新旧依赖关系?
int main () {
int a = 100;
std::cout<<&a<<std::endl;
auto a_copy = a; // deduced as int
std::cout<<&a_copy<<std::endl;
auto a_move = std::move(a); // deduced as int
std::cout<<&a_move<<std::endl;
};
输出:
0x7fffffffe094
0x7fffffffe098
0x7fffffffe09c
What's difference between default copy and std::move in that example?
没有区别。复制一些东西满足移动的要求,并且在内置类型的情况下,移动被实现为一个副本。
After move the object is there any dependence between new and old
不,没有依赖关系。两个变量都是独立的。
在这个例子中,没有区别。我们最终会得到 3 个 int
的值为 100。当然,不同的类型肯定会有差异。例如,让我们考虑类似 vector<int>
:
std::vector<int> a = {1, 2, 3, 4, 5}; // a has size 5
auto a_copy = a; // copy a. now we have two vectors of size 5
auto a_move = std::move(a); // *move* a into a_move
最后一个变量 a_move
拥有 a
的内部指针。所以我们最终得到的是 a_move
是一个大小为 5 的向量,但是 a
现在是空的。 move
比 copy
更有效(想象一下,如果它是 1000 个字符串的向量 - a_copy
将涉及分配 1000 个字符串的缓冲区并复制 1000 个字符串,但是 a_move
只是分配了几个指针)。
对于其他一些类型,一个可能无效:
std::unique_ptr<int> a{new int 42};
auto a_copy = a; // error
auto a_move = std::move(a); // OK, now a_move owns 42, but a points to nothing
对于许多类型,虽然没有区别:
std::array<int, 100> a;
auto a_copy = a; // copy 100 ints
auto a_move = std::move(a); // also copy 100 ints, no special move ctor
更一般地说:
T a;
auto a_copy = a; // calls T(const T& ), the copy constructor
auto a_move = std::move(a); // calls T(T&& ), the move constructor
使用 std::move
只是将左值更改为亡值,因此它可以与移动构造函数和移动赋值运算符一起使用。这些对于内置类型不存在,因此在此示例中使用 move 没有区别。
为了扩展其他发帖者的答案,移动即复制范式适用于所有由 POD 类型组成(或由 POD 类型组成的其他类型组成)的数据结构,如本例所示:
struct Foo
{
int values[100];
bool flagA;
bool flagB;
};
struct Bar
{
Foo foo1;
Foo foo2;
};
int main()
{
Foo f;
Foo fCopy = std::move(f);
Bar b;
Bar bCopy = std::move(b);
return 0;
}
在 Foo
和 Bar
的情况下,没有有意义的方法将数据从一个移动到另一个,因为它们最终都是 POD 类型的聚合 - none 它们的数据是间接拥有的(指向或引用其他内存)。因此,在这些情况下,移动是作为副本实现的,而原件(f
、b
)在 std::move()
行上的分配后保持不变。
只有使用动态分配的内存或独特的资源才能有意义地实现移动语义。