-
什么是右值引用?std::move到底是做什么的?到底移动语义是什么?为什么说移动更快??? |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 6 replies
-
前言在开始回答问题之前,我们首先要说明:C++11 引入的移动语义,本身逻辑其实是非常的简单的,但是新增的值类别和其规则是较为繁杂的,很多人之所以不会并且对移动语义抱有错误的幻想,无非是被一些互联网的错误想法影响的。 什么是右值引用?右值引用就是右值引用,它和左值引用一样,算是一种引用。不用想其他的东西,回归到语言上,问题的本身即可。 C++11 引入右值引用,并且引入了一整套的规则:值类别,即:左值、纯右值、亡值。
其实简单来说,就是将各种表达式分类,哪些是左值表达式,哪些是右值(纯右值和亡值都是右值)。右值引用只能被右值表达式初始化。 概念并不是我们的重点,默认各位了解一些基本的概念,以下示例能展示我们的意思: struct X{
X() = default;
X(const X& x){
// ...todo 进行资源的复制
}
X(X&& x)noexcept {
// ...todo 进行资源的移动
}
private:
// ...todo 很多的数据成员
};
开发者们约定移动构造这些右值引用的函数,是“转移所有权”。 你可以非常粗略的理解为,复制就是复制一份新的,但是移动呢,是把原对象的指向资源的指针,赋给新的对象成员,也就是所谓的转移所有权,通常的实现是转移指向数据的那个指针给新对象就行(当然了,这种移动是取决于你自己的移动构造移动赋值的实现的),自然没有复制开销,举一个标准库例子: #include <iostream>
#include <vector>
struct Test{};
int main(){
std::vector<Test>v;
v.emplace_back(Test{});
std::cout << &v[0] << '\n';
std::vector<Test> v2{ std::move(v) };
std::cout << &v2[0] << '\n';
} 打印的地址完全一样,代表并没有拷贝元素,而只是转移所有权,转移指向实际数据的指针。 一个左值表达式,要怎么匹配到右值版本的函数?通常我们会使用 std::move 到底是做什么的?
很多教程都会教你们,说 到底移动语义是什么?其实前面的内容已经讲的很清楚了,移动语义很简单,方便大家区分你到底要移动还是复制罢了。 我们可以自己实现一个支持移动语义的类就懂了,参见博客。 为什么说移动更快?这是一个非常非常经典的问题,并且错误想法众多,也是导致很多人对移动语义有不切实际幻想的根本原因。 很多人甚至觉得:移动一个平凡类型 (如 纯数据结构体),比复制要快? 完全属于是莫名其妙,我们前面已经说的很清楚了,移动之所以更快,在于大家约定了移动构造移动赋值等函数进行的是所有权的转移,而不是资源的拷贝,你要是想让移动慢,你直接 或者你说你写个 这里告诉各位:
总结我们省略了很多的语法规则和概念,这些东西需要学习,但却不是最重要的,明白设计和语义,其他的东西都是记住就好。 其他的规则等,各位自己学习。 |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
举一个Bjarne Stroustrup书中的例子说明什么是移动语义。 函数 vector<double> fill(istream& is) {
vector<double> res;
for (double x; is >> x;) res.push_back(x);
return res;
}
void use() {
vector<double> vec = fill(cin);
// ... use vec ...
} 函数 即直接将 移动语义通过移动构造函数和移动赋值实现,参数是右值引用。 // move constructor
vector::vector(vector&& v) :sz(v.sz), elem(v.elem) {
v.sz = 0;
v.elem = nullptr;
} 注:
|
Beta Was this translation helpful? Give feedback.
前言
在开始回答问题之前,我们首先要说明:C++11 引入的移动语义,本身逻辑其实是非常的简单的,但是新增的值类别和其规则是较为繁杂的,很多人之所以不会并且对移动语义抱有错误的幻想,无非是被一些互联网的错误想法影响的。
什么是右值引用?
右值引用就是右值引用,它和左值引用一样,算是一种引用。不用想其他的东西,回归到语言上,问题的本身即可。
C++11 引入右值引用,并且引入了一整套的规则:值类别,即:左值、纯右值、亡值。
其实简单来说,就是将各种表达式分类,哪些是左值表达式,哪些是右值(纯右值和亡值都是右值)。右值引用只能被右值表达式初始化。
概念并不是我们的重点,默认各位了解一些基本的概念,以下示例能展示我们的意思:
开发者们约定移动构造这些右值引用的函数,是“转移所有权”。
你可以非常粗略的理解为,复制就是复制一份新的,但是移动呢,是把原对象的指向资源的指针,赋给新的对象成员,也就是所谓的转移所有权,通常的实现是转移指向数据的那个指针给新对象就行(当然了…