Min*_*ine 8 c++ string vector move-semantics c++11
我原以为这std::make_move_iterator总会移动内容,但似乎没有.
看起来它正在移动元素vector<string>而不是移动元素vector<int>.
请参阅以下代码段:
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
void moveIntVector()
{
std::cout << __func__ << std::endl;
std::vector<int> v1;
for (unsigned i = 0; i < 10; ++i) {
v1.push_back(i);
}
std::vector<int> v2(
std::make_move_iterator(v1.begin() + 5),
std::make_move_iterator(v1.end()));
std::cout << "v1 is: ";
for (auto i : v1) {
std::cout << i << " ";
}
std::cout << std::endl;
std::cout << "v2 is: ";
for (auto i : v2) {
std::cout << i << " ";
}
std::cout << std::endl;
}
void moveStringVector()
{
std::cout << __func__ << std::endl;
std::vector<std::string> v1;
for (unsigned i = 0; i < 10; ++i) {
v1.push_back(std::to_string(i));
}
std::vector<std::string> v2(
std::make_move_iterator(v1.begin() + 5),
std::make_move_iterator(v1.end()));
std::cout << "v1 is: ";
for (auto i : v1) {
std::cout << i << " ";
}
std::cout << std::endl;
std::cout << "v2 is: ";
for (auto i : v2) {
std::cout << i << " ";
}
std::cout << std::endl;
}
int main()
{
moveIntVector();
moveStringVector();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
结果是:
moveIntVector
v1 is: 0 1 2 3 4 5 6 7 8 9 # I expect this should be `0 1 2 3 4` as well!
v2 is: 5 6 7 8 9
moveStringVector
v1 is: 0 1 2 3 4
v2 is: 5 6 7 8 9
Run Code Online (Sandbox Code Playgroud)
我正在Ubuntu 14.04, gcc 4.8.2编写代码-std=c++11
你能解释为什么std::make_move_iterator有不同的行为vector<int>和vector<string>?(或者它是一个错误吗?)
jua*_*nza 20
行为是预期的.两个向量的移动使得原始v1元素在下半部分中有5个移动元素.
不同之处在于,当移动字符串时,留下的是空字符串.这是因为它是一种非常有效的方式来移动字符串,并使移动的字符串处于自洽状态(从技术上讲,它们可以保留值"Hello, World, nice move!",但这会产生额外的成本).最重要的是,您不会在输出中看到那些移动的字符串.
在int向量的情况下,没有办法移动int比复制它更有效的方法,所以它们只是复制过来.
如果检查向量的大小,则v1在两种情况下都会看到大小为10.
这是一个简化的例子来说明从字符串移动是空的:
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
int main()
{
std::vector<std::string> v1{"a", "b", "c", "d", "e"};
std::vector<std::string> v2(std::make_move_iterator(v1.begin()),
std::make_move_iterator(v1.end()));
std::cout << "v1 size " << v1.size() << '\n';
std::cout << "v1: ";
for (const auto& s : v1) std::cout << s << " - ";
std::cout << '\n';
std::cout << "v2 size " << v2.size() << '\n';
std::cout << "v2: ";
for (const auto& s : v2) std::cout << s << " - ";
std::cout << '\n';
}
Run Code Online (Sandbox Code Playgroud)
输出:
v1 size 5
v1: - - - - -
v2 size 5
v2: a - b - c - d - e -
Run Code Online (Sandbox Code Playgroud)
当我们谈论移动时,我们并不是在谈论移动对象本身(它保持完整)。移动的是其内部数据。这可能会或可能不会影响内部数据被移动的对象的值。
这就是为什么int数组不丢失其原始ints的原因。对于您的字符串示例,它仍然std::strings像int示例一样具有原始字符串,但是其内部值已更改为空字符串。
重要的是要记住,在内部std::string(本质上)持有指向字符数组的指针。因此,当您复制 a 时,您将std::string复制字符数组的每个元素。一招,然而,避免做所有通过复制内部指针,而不是复制。
但是,如果移动操作在此停止,则将使std::strings指向相同的字符数组,并且更改其中一个指向的字符数据std::string也会更改另一个。因此,当移动字符串时,仅复制内部指针是不够的,您必须将指针的内部指针std::string从点移动到新的空白字符数组,以使其不再影响将其数据移至的字符串。 。
移动int时,在复制数据之后无需采取进一步的措施。由于不涉及任何指针,因此在复制之后,两个int都包含独立的数据。