c++编译器如何决定何时为std::vector或任何对象调用move构造函数?
How does a C++ compiler decide when to call a move constructor for std::vector or any object
我正在阅读std模板库书籍,并与STL容器章节中列出的以下详细信息混淆。显然,它指定了STD::VECTOR操作和
效果Operation Effect
vector<Elem> c(c2) | Copy constructor; creates a new vector as a copy of c2 (all elements are copied)
vector<Elem> c = c2 | Copy constructor; creates a new vector as a copy of c2 (all elements are copied)
vector<Elem> c(rv) | Move constructor; creates a new vector, taking the contents of the rvalue rv (since C++11)
vector<Elem> c = rv | Move constructor; creates a new vector, taking the contents of the rvalue rv (since C++11)
显然,移动构造函数和复制构造函数的语法没有区别,它们到底在什么时候被调用?
假设您有一个函数f
,它按值返回一个向量:
std::vector<int> f();
函数返回值为右值。
然后假设你想调用这个函数来初始化你的向量:
std::vector<int> v = f();
现在编译器知道由f
返回的向量将不再被使用,它是一个临时对象,因此复制这个临时对象是没有意义的,因为它将立即被销毁。所以编译器决定调用move构造函数。
move构造函数是在有意义的地方调用的,也就是说,移动一个对象之后再使用它是没有意义的,因为原始对象已经被修改了(可能),这是不可取的:
std::vector<int> a = { 1 };
std::vector<int> b = a; //Let's say this called move constructor
int value = a[0]; //value is possibly not 1, the value may have changed due to the move
因此,在这种情况下,复制构造函数被称为:
std::vector<int> a = { 1, 2 };
std::vector<int> b = a; //Copy constructor
但是,这里调用move构造函数,因为它被赋值给右值,或者临时值:
void foo(std::vector<int>) {}
foo({ 1, 2 }); //move constructor
向量{ 1, 2 }
是一个临时向量,谁在乎它是否被修改?你永远不会知道,因为一旦foo
结束,向量就会被破坏。复制临时向量只会浪费时间。
显然,移动构造函数和复制构造函数的语法没有区别
确实如此。这也不是std::vector
所特有的,但对于所有类型都是通用的。通过复制初始化和通过移动初始化具有完全相同的语法。复制分配也是如此。
区别在于实参表达式的类型。当实参是非constr值时,重载解析会优先使用move构造函数/赋值。否则,move-constructor不适用,所以使用copy constructor。
我假设rv只是一个像c2
一样的构造对象
rv和c2似乎不是对象。它们显然是表达式的占位符。这本书可以更清楚地说明这一点(也许是,毕竟节选断章取义了)。
也许您应该将语法与语义分离以便更好地理解。让我做一个类比,考虑以下代码:
struct A {
A(int i) {}
A(const std::string& s) {}
};
现在,如果您找到以下行,将调用哪个构造函数?
A a(x);
你不能告诉它,因为你不知道x
类型是int还是std::string。在您的示例中没有太大的不同,但是使用move语义,编译器将检查参数是否为右值。如果这样的A
类提供了(move)构造函数重载,并且x
是右值引用,那么它将被首选。
语法:classname (classname&,)
调用在一起看起来是一样的,但是它们的声明不同。
裁判:
http://en.cppreference.com/w/cpp/language/copy_constructorhttp://en.cppreference.com/w/cpp/language/move_constructor
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 在c++中用vector填充一个简单的动态数组
- vector.resize()中的分配错误
- 使用std::vector的OpenCL矩阵乘法
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- POCO::PostgreSQL:如何将std::vector支持添加到`Binder::bind`
- 在某些循环内使用vector.push_back时出现分段错误
- 当vector是tje全局变量时,c++中vector的内存管理
- 如何确定字符串是否包含在 std::vector 的任何字符串中
- 如何在任何一个轴上找到 std::vector<std::p air<int, int>> 上的 std::max_element?
- std :: vector用作堆栈和std :: stack之间是否存在任何复杂性差异
- 循环,直到没有遇到 std::vector 的任何元素
- "size_t"是否始终是"vector<int>::size_type"或任何其他容器类型的别名?
- "std::vector"会做任何我没有要求它做的事情吗
- 为什么std::vector::template在没有调用任何复制构造函数的情况下调用析构函数
- 当“std::vector”调整内存大小时,避免使用任何自动变量
- 删除绑定到成员函数的 vector<std::function<...>> 的任何元素
- 是否有任何函数可以对 std::vector< cv::P oint2f> 向量进行排序
- java arraylist有任何类似c++vector capacity()的函数,或者机制不同
- c++编译器如何决定何时为std::vector或任何对象调用move构造函数?