【发布时间】:2020-10-11 06:43:28
【问题描述】:
我正在使用移动控制器进行学习/刷新练习,但遇到了一些令我意想不到的事情。下面我有一个类person,其中包含一个std::string m_name;。我将其用作复制/移动 c'tors 的测试类。
这里是快速参考的代码:
#include <iostream>
#include <vector>
class person
{
public:
std::string m_name;
explicit person(const std::string &name) : m_name(name)
{
std::cout << "created " << m_name << std::endl;
}
~person()
{
std::cout << "destroyed " << m_name << std::endl;
}
person(const person &other) : m_name(other.m_name)
{
m_name += ".copied";
std::cout << "copied " << other.m_name << " -> " << m_name << std::endl;
}
person(const person &&other) noexcept : m_name(std::move(other.m_name))
{
m_name += ".moved";
std::cout << "moved " << other.m_name << " -> " << m_name << std::endl;
}
};
int main()
{
std::vector<person> people;
people.reserve(10);
std::cout << "\ncopy bob (lvalue):" << std::endl;
person bob{"bob"};
people.push_back(bob);
std::cout << "\nmove fred (lvalue):" << std::endl;
person fred{"fred"};
people.push_back(std::move(fred));
std::cout << "\ntemp joe (rvalue):" << std::endl;
people.push_back(person{"joe"});
std::cout << "\nterminating:" << std::endl;
}
这给了我我期望的输出(主要是,除了为什么 std::string 内容没有“移动”?):https://godbolt.org/z/-J_56i
然后我删除 std::vector reserve 以便 std::vector 在我添加元素时必须“增长”。现在我得到了一些我真的没想到的东西:https://godbolt.org/z/rS6-mj
现在我可以看到 bob 被复制,然后在添加 fred 时移动,然后在添加 joe 时再次移动。我的印象是 std::vector 在必须重新分配空间时“移动”了。但我认为它执行的是内存复制/移动,而不是逐个对象的复制/移动。真没想到它会调用move构造函数。
现在如果我删除 move c'tor,我发现 bob 被复制了三遍!:https://godbolt.org/z/_BxnvU 这似乎效率很低。
来自 cplusplus.com:
push_back()
Add element at the end 在向量的末尾添加一个新元素, 在其当前的最后一个元素之后。 val 的内容被复制(或 移动)到新元素。
这实际上将容器大小增加了一倍,从而导致 当且仅当-时自动重新分配分配的存储空间 新的向量大小超过了当前向量的容量。
调整大小()
调整容器大小,使其包含 n 个元素。
如果 n 小于当前容器大小,则内容为 减少到它的前 n 个元素,删除那些超出的元素(并销毁 他们)。
如果 n 大于当前容器大小,则内容为 通过在末尾插入尽可能多的元素来扩展 n的大小。如果指定了 val,则新元素被初始化为 val 的副本,否则,它们是值初始化的。
如果 n 也大于当前容器容量,则自动 重新分配已分配的存储空间。
注意这个函数改变了容器的实际内容 通过插入或删除其中的元素。
我猜它并没有真正描述它“如何”重新分配,但是内存副本肯定是将向量移动到其新分配的内存空间的最快方法?
那么为什么在添加 std::vector 而不是内存副本时调用复制/移动 c'tors?
附注/问题:(任何可能这应该是一个单独的问题):亲自移动 c'tor 为什么打印 moved fred -> fred.moved 而不是 moved -> fred.moved。看来 std::string 移动分配并没有真正“移动”数据......
【问题讨论】:
-
but surely a memory copy is the fastest way to move the vector to its newly allocated memory space?你不能只 memcpy C++ 对象。如果它们包含指向自身的指针怎么办? -
这是一个很好的观点,这意味着分配给向量可能会比我想象的更糟! - 特别是如果您创建的课程没有移动 c'tors :o。如果可以的话,我想总是保留一些空间:)
-
这个问题可能很快就会得到解决:quuxplusone.github.io/blog/2018/07/18/…
标签: c++ c++11 vector move-semantics