想象一下,你有很多重载的方法(在C++ 11之前)看起来像这样:
class MyClass {
public:
void f(const MyBigType& a, int id);
void f(const MyBigType& a, string name);
void f(const MyBigType& a, int b, int c, int d);
// ...
};
Run Code Online (Sandbox Code Playgroud)
这个函数复制了a(MyBigType),所以我想通过提供一个版本f来移动a而不是复制它来添加优化.
我的问题是,现在f重载次数将重复:
class MyClass {
public:
void f(const MyBigType& a, int id);
void f(const MyBigType& a, string name);
void f(const MyBigType& a, int b, int c, int d);
// ...
void f(MyBigType&& a, int id);
void f(MyBigType&& a, string …Run Code Online (Sandbox Code Playgroud) 在C++ 11中,std::move当我们想要将值移动(破坏性地复制)到容器中时,我们可以提高效率:
SomeExpensiveType x = /* ... */;
vec.push_back(std::move(x));
Run Code Online (Sandbox Code Playgroud)
但我找不到任何其他方式.我的意思是这样的:
SomeExpensiveType x = vec.back(); // copy!
vec.pop_back(); // argh
Run Code Online (Sandbox Code Playgroud)
这在适配器上更常见(copy-pop)stack.可能存在这样的事情:
SomeExpensiveType x = vec.move_back(); // move and pop
Run Code Online (Sandbox Code Playgroud)
为了避免副本?这已经存在了吗?我在n3000中找不到类似的东西.
我有一种感觉,我错过了一些非常明显的东西(比如它的不必要),所以我准备好了"ru dum".:3
我有一个untemplated仿函数对象,我试图存储为std::function另一个对象内部.这个对象非常重量级,因此它被标记为不可复制,但它确实有一个移动构造函数.但是,尝试从临时构造函数构造std :: function或分配它失败.
这是引发错误的最小示例.
// pretend this is a really heavyweight functor that can't be copied.
struct ExampleTest
{
int x;
int operator()(void) const {return x*2;}
ExampleTest( ) :x(0){}
ExampleTest( int a ) :x(a){}
// allow move
ExampleTest( ExampleTest &&other ) :x(other.x) {};
private: // disallow copy, assignment
ExampleTest( const ExampleTest &other );
void operator=( const ExampleTest &other );
};
// this sometimes stores really big functors and other times stores tiny lambdas.
struct ExampleContainer
{
ExampleContainer( int …Run Code Online (Sandbox Code Playgroud) 以下编译和运行(在Apple LLVM版本6.1.0和Visual C++ 2015下):
#include <functional>
#include <iostream>
struct s { int x; };
int main(int argc, char **argv)
{
std::function<void (s &&)> f = [](const s &p) { std::cout << p.x; };
f(s {1});
return 0;
}
Run Code Online (Sandbox Code Playgroud)
为什么分配不会std::function<void (s &&)> f = [](const s &p) { std::cout << p.x; };产生错误?接受右值引用的函数不应该与接受const左值引用的函数具有相同的签名,如果它?const从lambda声明中删除确实会产生预期的错误.
当然,这不会编译:
int &z = 3; // error: invalid initialization of non-const reference ....
Run Code Online (Sandbox Code Playgroud)
这将编译:
const int &z = 3; // OK
Run Code Online (Sandbox Code Playgroud)
现在,考虑一下:
const int y = 3;
int && yrr = y; // const error (as you would expect)
int && yrr = move(y); // const error (as you would expect)
Run Code Online (Sandbox Code Playgroud)
但这些下一行确实为我编译.我认为不应该.
int && w = 3;
int && yrr = move(3);
void bar(int && x) {x = 10;}
bar(3);
Run Code Online (Sandbox Code Playgroud)
最后两行不会允许文字3被修改吗?3与const int有什么区别?最后,"修改"文字是否有任何危险?
(g ++ - 4.6(GCC)4.6.2 with …
一篇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?
编译器一直在抱怨我试图将左值绑定到右值引用,但我看不出如何.我是C++ 11的新手,移动语义等,所以请耐心等待.
我有这个功能:
template <typename Key, typename Value, typename HashFunction, typename Equals>
Value& FastHash<Key, Value, HashFunction, Equals>::operator[](Key&& key)
{
// Some code here...
Insert(key, Value()); // Compiler error here
// More code here.
}
Run Code Online (Sandbox Code Playgroud)
它调用这个方法:
template <typename Key, typename Value, typename HashFunction, typename Equals>
void FastHash<Key, Value, HashFunction, Equals>::Insert(Key&& key, Value&& value)
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
我不断收到如下错误:
cannot convert argument 1 from 'std::string' to 'std::string &&'
Run Code Online (Sandbox Code Playgroud)
在Insert()调用上.是不是key在运算符重载中定义为右值?为什么它被重新解释为左值?
谢谢.
std::initializer_list我所看到的大多数C++ 11代码都是按值来获取的,但有时它是由右值引用获取的.这样做有什么好的理由吗?
例如,我遇到的几乎所有例子都是这样的:
class A {
public:
A(std::initializer_list<int>);
};
Run Code Online (Sandbox Code Playgroud)
但我偶尔会看到这件事:
class B {
public:
B(std::initializer_list<int> &&);
};
Run Code Online (Sandbox Code Playgroud)
我理解一般的rvalue引用的用途和目的,但为什么在a的情况下,其中一个优先于另一个std::initializer_list?我唯一能想到的是class A允许初始化列表单独构建,并class B防止这种情况发生.
std::initializer_list<int> values {1,2,3,4};
A a(values); // valid
B b(values); // error
Run Code Online (Sandbox Code Playgroud)
但我想不出一个很好的理由,为什么要防止这是一件令人满意的事情.
那么,为什么会std::initializer_list采用右值参考而不是值?
我试图给出一个导致rvalue的操作的简单示例.
这个测试用例应该有效,但令人惊讶的是(对我而言),添加两个ints 的结果不是rvalue(引用).我在这里错过了什么?
void test(int i, int j)
{
// this assert should pass, but fails:
static_assert(std::is_same<decltype(i + j), int&&>(), "i + j should be a rvalue");
// this assert passed, but should fail:
static_assert(std::is_same<decltype(i + j), int>(), "this assert should fail...");
}
Run Code Online (Sandbox Code Playgroud) 我不能这样做:
int &&q = 7;
int &&r = q;
//Error Message:
//cannot convert from 'int' to 'int &&'
//You cannot bind an lvalue to an rvalue reference
Run Code Online (Sandbox Code Playgroud)
如果我理解正确,在初始化右值引用时,也会初始化一个临时变量.所以int &&q = 7;可以认为是:
int temp = 7;
int &&q = temp;
Run Code Online (Sandbox Code Playgroud)
当在右侧使用参考时,我实际上是在使用裁判.所以int &&r = q;可以认为是:
int &&r = temp; //bind an lvalue to an rvalue reference, cause error, understandable
Run Code Online (Sandbox Code Playgroud)
所以上面是我理解编译器错误发生的方式.
为什么添加std::forward可以解决?
int &&q = 7;
int &&r = std::forward<int>(q);
Run Code Online (Sandbox Code Playgroud)
我知道std::forward总是返回一个右值引用,引用的引用是如何std::forward不同的int&&q?