为什么下面的代码可以编译通过?
#include <vector>
#include <iostream>
struct Foo {
std::vector<int> bar = {1, 2, 3};
};
int main()
{
Foo foo1;
const Foo& foo2 = foo1;
std::vector<int> target;
std::move(foo2.bar.begin(), foo2.bar.end(), std::back_inserter(target));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
std::move的文档说
在此操作之后,移出范围中的元素仍将包含适当类型的有效值,但不一定与移动之前的值相同。
所以这实际上可以改变对象 foo2,即使它被声明为 const。为什么这有效?
12.8复制和移动类对象[class.copy]§31和§32说:
在具有类返回类型的函数的return语句中,当表达式是具有与函数返回类型相同的cv-unqualified类型的非易失性自动对象(函数或catch子句参数除外)的名称时,通过将自动对象直接构造到函数的返回值中,可以省略复制/移动操作
当满足或将满足复制操作的省略标准时,除了源对象是函数参数这一事实,并且要复制的对象由左值指定,重载决策选择复制的构造函数是首先执行,好像对象是由右值指定的.
因此我们可以写:
unique_ptr<int> make_answer()
{
unique_ptr<int> result(new int(42));
return result; // lvalue is implicitly treated as rvalue
}
Run Code Online (Sandbox Code Playgroud)
但是,我注意到g ++ 4.6.3也接受不是名称的左值,例如:
return (result);
return *&result;
return true ? result : result;
Run Code Online (Sandbox Code Playgroud)
相比之下,return rand() ? result : result;不起作用.编译器的优化器是否会干扰语言语义?当我解释标准时,return (result);不应该编译,因为(result)它不是名称,而是带括号的表达式.我是对还是错?
可能重复:
C++ 11 rvalues并且移动语义混乱
我认为是正确的
std::string GetLine()
{
std::string str;
std::getline(std::cin, str);
return std::move(str);
}
Run Code Online (Sandbox Code Playgroud)
但是在这个链接http://www.cprogramming.com/c++11/rvalue-references-and-move-semantics-in-c++11.html (检查标题部分返回一个明确的右值引用功能)
这是#1谷歌搜索命中移动语义显示类似的功能签名
int&& GetInt()
{
int x = 0;
// code here
return std::move(x);
}
Run Code Online (Sandbox Code Playgroud)
从我在其他地方读到的&&表示右值引用,所以在这种情况下它返回对不存在的对象的引用.
那是哪个呢?
(是的,我知道移动一个int没有真正的好处,但问题是在第一个函数中是否使用std :: string或std :: string &&的返回类型.如果这是应该对所有类型执行的方式.)
当前的C++ 11标准不支持在lambda表达式中移动捕获变量
unique_ptr<int[]> msg(new int[1000000]);
async_op([&&msg] { // compile error : move capture is not supported
/* do something */
});
Run Code Online (Sandbox Code Playgroud)
由于消息传递和唯一所有权在某些异步系统设计中具有一定的关键作用,我认为移动语义应该被视为一级语言语义.但是lambda不支持移动捕获.
当然,我知道,有一些解决方法使用移动捕获代理-但我不知道的原因,这个功能不被包括在C++ 11标准,尽管它的重要性决定的.
最近,我用rvalues"玩"了解他们的行为.大多数结果并没有让我惊讶,但后来我看到如果我抛出一个局部变量,就会调用移动构造函数.
在那之前,我认为移动语义规则的目的是保证只有当编译器能够检测到它不再被使用时(如在临时对象中)或者用户不承诺时,对象才会移动(并变为无效).使用它(如在std :: move中).
但是,在下面的代码中,没有这个条件,并且我的变量仍然被移动(至少在g ++ 4.7.3上).
这是为什么?
#include <iostream>
#include <string>
using namespace std;
int main() {
string s="blabla";
try {
throw s;
}
catch(...) {
cout<<"Exception!\n";
}
cout<<s; //prints nothing
}
Run Code Online (Sandbox Code Playgroud) 在C++ 14中,lambda表达式可以通过使用捕获初始化器从它们移动来捕获变量.但是,这会使得结果闭包对象不可复制.如果我有一个带有std::function参数的现有函数(我无法改变),我无法传递闭包对象,因为std::function构造函数需要给定的函子CopyConstructible.
#include <iostream>
#include <memory>
void doit(std::function<void()> f) {
f();
}
int main()
{
std::unique_ptr<int> p(new int(5));
doit([p = std::move(p)] () { std::cout << *p << std::endl; });
}
Run Code Online (Sandbox Code Playgroud)
这会出现以下错误:
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:1911:10: error:
call to implicitly-deleted copy constructor of '<lambda at test.cpp:10:7>'
new _Functor(*__source._M_access<_Functor*>());
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:1946:8: note: in
instantiation of member function 'std::_Function_base::_Base_manager<<lambda at test.cpp:10:7>
>::_M_clone' requested here
_M_clone(__dest, __source, _Local_storage());
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:2457:33: note: in
instantiation of member function 'std::_Function_base::_Base_manager<<lambda at test.cpp:10:7>
>::_M_manager' …Run Code Online (Sandbox Code Playgroud) 我注意到在Rust中移动应用于左值,并且静态强制执行不移动的对象.
这些语义如何与Clean和Mercury中的唯一性类型相关?它们是相同的概念吗?如果没有,它们有何不同?
有人能解释一下这段代码的执行顺序吗?
struct Foo {
~Foo() {
std::cout << "1";
}
};
Run Code Online (Sandbox Code Playgroud)
int main() {
const Foo& bar = Foo();
const Foo& baz = std::move(Foo());
std::cout << "2";
}
Run Code Online (Sandbox Code Playgroud)
以下代码打印121.
我明白为什么我在 2 之后得到 1,这是因为对象的生命周期绑定到它执行的代码块,而且我也知道右值可以绑定到左值 const 引用,但是为什么立即调用移动对象的析构函数?这是什么原因呢?这个析构函数到底在哪里被调用?
给定基类 A 和派生类 B,A 删除了移动构造函数:
class A {
public:
A() {}
A(const A&) = default;
A(A&&) = delete;
};
class B : public A
{
};
Run Code Online (Sandbox Code Playgroud)
在这种情况下,由于删除了移动构造函数,以下函数无法编译:
A f() {
A a;
return a;
}
Run Code Online (Sandbox Code Playgroud)
但 B 的类似函数不会报告任何错误:
B g() {
B b;
return b;
}
Run Code Online (Sandbox Code Playgroud)
这是否意味着B中的移动构造函数没有被删除?我想知道标准中的规则是什么。
请考虑以下代码:
std::vector vec;
vec.reserve(500);
size_t cap = vec.capacity();
std::vector newVec = std::move(vec);
assert(cap == newVec.capacity());
Run Code Online (Sandbox Code Playgroud)
在几乎任何你遇到的实现中,这都可行.我不关心实现什么.我想知道标准需要什么.移动的vector容量是否与原始容量相同?或者断言触发器?
move-semantics ×10
c++ ×9
c++11 ×5
lambda ×2
c++14 ×1
constructor ×1
destructor ×1
exception ×1
inheritance ×1
lifetime ×1
mercury ×1
return ×1
rust ×1
stdmove ×1
stdvector ×1