我试图更好地理解移动在用于将元素插入STL容器时的工作方式。我正在查看一个代码,其中使用new(在堆上创建)分配了一个对象。稍后,当插入完成时,似乎STL容器分配一个新对象并调用移动构造函数。有没有办法让STL容器直接使用该对象(接管已分配的对象(ptr))。
我有一些其他问题的示例代码:
#include <iostream>
#include <vector>
using namespace std;
class foo
{
public:
string s1;
foo() = default;
foo(const foo& fm)
{ cout << "copy ctor" << endl; }
foo(const foo&& fm)
{ cout << "move ctor" << endl; }
foo& operator= (const foo& fm)
{ cout << "copy assign" << endl; return *this; }
};
vector<foo> vec_f;
int main()
{
foo f1;
vec_f.push_back(f1);
cout << endl;
foo f2;
vec_f.push_back(move(f2));
cout << endl;
foo *f3 = new (foo);
vec_f.push_back(*f3);
cout << endl;
foo *f4 = new (foo);
vec_f.push_back(move(*f4));
cout << endl;
}
输出如下:
copy ctor
move ctor
copy ctor
copy ctor
copy ctor
copy ctor
move ctor
f1:foo是使用copy ctor创建的。但是,这个对象是由于STL代码执行新的OR部分而创建的,这个OR部分是通过值将对象传递给函数(与STL无关,而是编译器事物)?我在猜测后者。如果是这样,当元素插入容器时,对象创建在哪里?
f2:foo是使用移动ctor,通过STL代码创建的,对吗?为什么/如何立即调用复制ctor?是因为f2是在堆栈上创建的(不是堆)?如果是这样,STL代码如何计算出来?
f3:最让我困惑的是。猜测第一个副本ctor是作为通过值传递参数的一部分而调用的(与STL无关)。如何/为什么其他两个副本被称为。f4:STL调用move ctor,所以移动ctor可以使用foo对象的内容。是否可以使STL代码只使用ptr(因为它是在堆上创建的)。我的理解是STL容器中的对象无论如何都是在堆上创建的。
很抱歉这篇长篇文章。希望有人能说清楚。
此致 艾哈迈德。
答案 0 :(得分:0)
首先要意识到的是std::move
实际上并没有移动一个对象。它会在哪里移动到?它只允许从移动。
要意识到的第二件事是vector
管理自己的记忆。您可以将许多对象移动到vector
,但是您无法将vector
内存放在其旁边(在这种情况下,您根本不会移动对象)
接下来是vector::push_back
。这可以采用T const&
或T&&
,具体取决于参数。只有后一种情况才有适当的形式直接将值移动到vector
。第一个和第三个案例失败,因为无法移动使用的表达式。第二种情况看起来没有进行优化(副本可能会在发布版本中进行优化)。
答案 1 :(得分:0)
由于vector
尺寸更改的重新分配,vector
本身会进行额外的复制和移动。
您可以打印内存地址,例如cout << &vec_f[0] << endl;
,并在每push_back()
示例输出:
copy ctor
0077C350
move ctor
move ctor
0077C588
move ctor
move ctor
copy ctor
0077C690
move ctor
move ctor
move ctor
move ctor
0077C8A8
如果您在vec_f.reserve(4);
之后添加vector<foo> vec_f;
,则输出将为:
copy ctor
0087C308
move ctor
0087C308
copy ctor
0087C308
move ctor
0087C308
应该是你的期望。
P.S。我正在使用VS2013 Express。