std::move 的用法
Usages of std::move
问题下方是SO代码的简化版本。原代码:
- 收到不应修改或无效的结构
- 创建一个不同的结构,其中包含从原始结构复制的一些数据
- 新创建的结构是不可修改的,所有成员都是
const
- 新创建的结构不能有知道原始结构的构造函数
SO的简化代码没有原来的结构,我只是用循环编造了数据。然而,仍然重要的细节是新结构的构造函数将被传递 std::vector
。这些在循环中填充并移动到新结构
我突然想到,在制作新结构后将不需要 std::vector
,因此 std::move
将是合适的。我在下面的代码中将用法标记为“移动 1”、“移动 2”、“移动 3”和“移动 4”:
#include <iostream>
#include <vector>
struct A {
const int m_a;
A() = delete;
A(const int a_a) : m_a(a_a) {}
void display() const { std::cout << " " << m_a << "\n"; }
};
struct B {
const std::vector<A> m_as;
const int m_b;
B() = delete;
B(
std::vector<A>&& a_as,
const int a_b
) :
m_as(std::move(a_as)), // Move 1
m_b(a_b)
{}
void display() const {
std::cout << " " << m_b << ":\n";
for (const A& a : m_as)
a.display();
}
};
struct C {
const std::vector<B> m_bs1;
const std::vector<B> m_bs2;
C() = delete;
C(
std::vector<B>&& a_bs1,
std::vector<B>&& a_bs2
) :
m_bs1(std::move(a_bs1)), // Move 2
m_bs2(std::move(a_bs2)) // Move 2
{}
void display() const {
std::cout << "0:\n";
for (const B& b : m_bs1)
b.display();
std::cout << "1:\n";
for (const B& b : m_bs2)
b.display();
}
};
int main() {
// Manually making up data, actual usage will take data from a different
// kind of structure and populate vectors
std::vector<B> bs1, bs2;
for (int i = 0; i < 3; ++i) {
std::vector<A> as;
for (int j = 0; j < 2; ++j)
as.emplace_back(j);
bs1.emplace_back(std::move(as), i); // Move 3
}
for (int i = 0; i < 3; ++i) {
std::vector<A> as;
for (int j = 0; j < 2; ++j)
as.emplace_back(j);
bs2.emplace_back(std::move(as), i); // Move 3
}
C c(std::move(bs1), std::move(bs2)); // Move 4
c.display();
return 0;
}
一些假设:
- 我认为“Move 1”和“Move 2”之间没有显着差异
- 我认为“Move 3”和“Move 4”之间没有显着差异
- 据我所知,
std::forward
不能很好地替代任何 std::move
用法,因为没有模板
问题:
std::move
的所有用法都有意义还是没有必要?
您可以看到大部分 std::move
是必需的,只需删除它们,您的代码将无法编译。唯一的例外是 Move 1
和 Move 2
,代码在没有它们的情况下仍然可以编译,但这只是因为调用了 std::vector
复制构造函数。
如果您想从一个对象中移动,您几乎总是需要使用 std::move
,唯一的例外是从临时对象中移动和返回对象时。
问题下方是SO代码的简化版本。原代码:
- 收到不应修改或无效的结构
- 创建一个不同的结构,其中包含从原始结构复制的一些数据
- 新创建的结构是不可修改的,所有成员都是
const
- 新创建的结构不能有知道原始结构的构造函数
SO的简化代码没有原来的结构,我只是用循环编造了数据。然而,仍然重要的细节是新结构的构造函数将被传递 std::vector
。这些在循环中填充并移动到新结构
我突然想到,在制作新结构后将不需要 std::vector
,因此 std::move
将是合适的。我在下面的代码中将用法标记为“移动 1”、“移动 2”、“移动 3”和“移动 4”:
#include <iostream>
#include <vector>
struct A {
const int m_a;
A() = delete;
A(const int a_a) : m_a(a_a) {}
void display() const { std::cout << " " << m_a << "\n"; }
};
struct B {
const std::vector<A> m_as;
const int m_b;
B() = delete;
B(
std::vector<A>&& a_as,
const int a_b
) :
m_as(std::move(a_as)), // Move 1
m_b(a_b)
{}
void display() const {
std::cout << " " << m_b << ":\n";
for (const A& a : m_as)
a.display();
}
};
struct C {
const std::vector<B> m_bs1;
const std::vector<B> m_bs2;
C() = delete;
C(
std::vector<B>&& a_bs1,
std::vector<B>&& a_bs2
) :
m_bs1(std::move(a_bs1)), // Move 2
m_bs2(std::move(a_bs2)) // Move 2
{}
void display() const {
std::cout << "0:\n";
for (const B& b : m_bs1)
b.display();
std::cout << "1:\n";
for (const B& b : m_bs2)
b.display();
}
};
int main() {
// Manually making up data, actual usage will take data from a different
// kind of structure and populate vectors
std::vector<B> bs1, bs2;
for (int i = 0; i < 3; ++i) {
std::vector<A> as;
for (int j = 0; j < 2; ++j)
as.emplace_back(j);
bs1.emplace_back(std::move(as), i); // Move 3
}
for (int i = 0; i < 3; ++i) {
std::vector<A> as;
for (int j = 0; j < 2; ++j)
as.emplace_back(j);
bs2.emplace_back(std::move(as), i); // Move 3
}
C c(std::move(bs1), std::move(bs2)); // Move 4
c.display();
return 0;
}
一些假设:
- 我认为“Move 1”和“Move 2”之间没有显着差异
- 我认为“Move 3”和“Move 4”之间没有显着差异
- 据我所知,
std::forward
不能很好地替代任何std::move
用法,因为没有模板
问题:
std::move
的所有用法都有意义还是没有必要?
您可以看到大部分 std::move
是必需的,只需删除它们,您的代码将无法编译。唯一的例外是 Move 1
和 Move 2
,代码在没有它们的情况下仍然可以编译,但这只是因为调用了 std::vector
复制构造函数。
如果您想从一个对象中移动,您几乎总是需要使用 std::move
,唯一的例外是从临时对象中移动和返回对象时。