在Rust中,有两种可能性来引用
借用,即参考,但不允许改变参考目的地.该&运营商借用值所有权.
可变地借用,即参考改变目的地.该&mut运营商性情不定地借用一个值所有权.
首先,任何借入必须持续不超过所有者的范围.其次,您可能拥有这两种借款中的一种或另一种,但不能同时使用这两种:
- 一个或多个
&T资源的引用(),- 一个可变的引用(
&mut T).
我相信引用一个引用是创建一个指向值的指针并通过指针访问该值.如果存在更简单的等效实现,则编译器可以优化它.
但是,我不明白什么是移动的意思以及它是如何实现的.
对于实现Copy特征的类型,它意味着复制,例如通过从源分配结构成员,或者a memcpy().对于小结构或原始数据,此副本是有效的.
而对于招?
如何添加和删除元素"重新缩放"数据?如何计算矢量的大小(我相信它是跟踪的)?任何其他额外的资源来了解矢量将不胜感激.
一篇C++ Next博客文章说
A compute(…)
{
A v;
…
return v;
}
Run Code Online (Sandbox Code Playgroud)
如果A具有可访问的副本或移动构造函数,则编译器可以选择忽略该副本.否则,如果A有移动构造函数,v则移动.否则,如果A有复制构造函数,v则复制.否则,将发出编译时错误.
我以为我应该总是返回值,std::move
因为编译器能够找出用户的最佳选择.但另一个例子来自博客文章
Matrix operator+(Matrix&& temp, Matrix&& y)
{ temp += y; return std::move(temp); }
Run Code Online (Sandbox Code Playgroud)
这std::move是必要的,因为y必须将其视为函数内的左值.
啊,在研究这篇博文之后,我的脑袋几乎爆炸了.我尽力去理解推理,但是我学的越多,我就越困惑.我们为什么要借助于这个价值来回报这个价值std::move?
考虑以下:
struct vec
{
int v[3];
vec() : v() {};
vec(int x, int y, int z) : v{x,y,z} {};
vec(const vec& that) = default;
vec& operator=(const vec& that) = default;
~vec() = default;
vec& operator+=(const vec& that)
{
v[0] += that.v[0];
v[1] += that.v[1];
v[2] += that.v[2];
return *this;
}
};
vec operator+(const vec& lhs, const vec& rhs)
{
return vec(lhs.v[0] + rhs.v[0], lhs.v[1] + rhs.v[1], lhs.v[2] + rhs.v[2]);
}
vec&& operator+(vec&& lhs, const vec& rhs)
{
return move(lhs += …Run Code Online (Sandbox Code Playgroud) 该程序试图将一个字符串移出一个函数并用它来构造另一个字符串:
#include <iostream>
#include <string>
#include <utility>
std::string && Get_String(void);
int main(){
std::string str{Get_String()};
std::cout << str << std::endl;
return 0;
}
std::string && Get_String(void){
std::string str{"hello world"};
return std::move(str);
}
Run Code Online (Sandbox Code Playgroud)
程序编译,但执行时会出现段错误.
这是我的理由: Get_String将创建一个本地字符串.在字符串超出范围之前,需要创建并返回该字符串的副本.该副本将用于在main中构造字符串.但是,如果我将字符串移出函数,则不需要复制.
为了理解移动语义,有人可以解释为什么我在做什么,可能没有任何意义.是否可以将对象移出函数?
编辑:
如果我更改函数签名,它编译并正确运行:
std::string && Get_String(void);
Run Code Online (Sandbox Code Playgroud)
至
std::string Get_String(void);
Run Code Online (Sandbox Code Playgroud)
在这种情况下,在返回期间移动字符串是否仍然更有效?
假设我有以下代码:
class B { /* */ };
class A {
vector<B*> vb;
public:
void add(B* b) { vb.push_back(b); }
};
int main() {
A a;
B* b(new B());
a.add(b);
}
Run Code Online (Sandbox Code Playgroud)
假设在这种情况下,B*可以处理所有原始指针unique_ptr<B>.
令人惊讶的是,我无法找到如何使用转换此代码unique_ptr.经过几次尝试,我想出了以下代码,它编译:
class A {
vector<unique_ptr<B>> vb;
public:
void add(unique_ptr<B> b) { vb.push_back(move(b)); }
};
int main() {
A a;
unique_ptr<B> b(new B());
a.add(move(b));
}
Run Code Online (Sandbox Code Playgroud)
所以我的简单问题是:这是实现它的方式,特别是,这是move(b)唯一的方法吗?(我在想rvalue引用,但我不完全理解它们.)
如果你有一个完整的移动语义解释链接unique_ptr,我无法找到,请不要犹豫,分享它.
编辑根据http://thbecker.net/articles/rvalue_references/section_01.html,我的代码似乎没问题.
实际上,std :: move只是语法糖.对于类X的对象x,move(x)与以下内容相同:
static_cast <X&&>(x)
Run Code Online (Sandbox Code Playgroud)
需要这两个移动函数,因为转换为右值引用:
可能重复:
有人可以向我解释移动语义吗?
有人能指出一个好的来源或在这里解释什么是移动语义?
参考http://en.wikipedia.org/wiki/Copy_elision
我运行下面的代码:
#include <iostream>
struct C {
C() {}
C(const C&) { std::cout << "Hello World!\n"; }
};
void f() {
C c;
throw c; // copying the named object c into the exception object.
} // It is unclear whether this copy may be elided.
int main() {
try {
f();
}
catch(C c) { // copying the exception object into the temporary in the exception declaration.
} // It is also unclear whether this copy may be …Run Code Online (Sandbox Code Playgroud) 是否有任何一点实现移动构造函数并为仅包含基本类型的结构或类移动赋值运算符?例如,
struct Foo
{
float x;
float y;
float z;
/// ... ctor, copy ctor, assignment overload, etc...
};
Run Code Online (Sandbox Code Playgroud)
我可以看到,如果我有更复杂的东西,比如:
struct Bar
{
float x,y,z;
std::string Name;
};
Run Code Online (Sandbox Code Playgroud)
我宁愿移动而Name不是复制它,移动ctor会有意义.然而,"移动"浮动并不(语义上)对我有意义.
思考?
特定
void foo( int&& x ) {
std::cout << &x;
}
Run Code Online (Sandbox Code Playgroud)
这有效,但这个地址实际上代表了什么?int调用foo时是否是临时创建的,这是地址所代表的内容?如果这是真的,如果我写int y = 5; foo(static_cast<int&&>(y));,这是否会导致另一个临时创建或编译器智能地引用y?