我想知道一个右值引用成员有什么用
class A {
// ...
// Is this one useful?
Foo &&f;
};
Run Code Online (Sandbox Code Playgroud)
与左值参考成员相比,它有任何好处或缺点吗?什么是它的主要用途?
让我们看一下表达式模板的一个特殊优点:ET可用于避免在重载运算符中出现的内存中的矢量大小临时值,如:
template<typename T>
std::vector<T> operator+(const std::vector<T>& a, const std::vector<T>& b)
{
std::vector<T> tmp; // vector-sized temporary
for_each(...);
return tmp;
}
Run Code Online (Sandbox Code Playgroud)
在C++ 11中,此函数的return语句应用移动语义.没有矢量的副本.这是一场胜利.
但是,如果我看一个像这样的简单表达式
d = a + b + c;
Run Code Online (Sandbox Code Playgroud)
我看到上面的函数被调用两次(两者都有operator+),而最后的赋值可以用移动语义来完成.
总共执行2个循环.意思是我把一个临时的,然后读回来.对于大向量,这不属于缓存.这比表达模板更糟糕.他们可以在一个循环中完成整个过程.ET可以执行上述代码,相当于:
for(int i=0 ; i < vec_length ; ++i)
d[i] = a[i] + b[i] + c[i];
Run Code Online (Sandbox Code Playgroud)
我想知道lambdas与移动语义或任何其他新功能一起是否可以像ET一样好.有什么想法吗?
编辑:
基本上,使用ET技术,编译器构建一个解析树,类似于代数表达式和它的类型系统.该树由内部节点和叶子节点组成.内部节点表示操作(加法,乘法等),叶节点表示对数据对象的引用.
我尝试以堆栈计算机的方式考虑整个计算过程:从操作堆栈中获取操作并从参数堆栈中提取下一个参数并评估操作.将结果放回堆栈等待操作.
为了表示这两个不同的对象(操作堆栈和数据叶堆栈),我将一个捆绑在一起std::tuple用于操作,一个
捆绑在一起std::tuple用于数据std::pair<>.最初我使用了a std:vector但导致了运行时开销.
整个过程分为两个阶段:堆栈机器初始化,其中初始化操作和参数堆栈.以及通过将配对的容器分配给向量来触发的评估阶段.
我创建了一个Vec包含私有array<int,5>(有效负载)的类,它具有一个带有"表达式"的重载赋值运算符.
operator*对于所有拍摄Vec和"表达"的组合,全局都会超负荷,
以便在我们不仅仅是的情况下也能正确处理a*b.(注意,我将这个教育示例转换为乘法 - 基本上是为了快速发现imull汇编程序.) …
假设我有以下代码:
#include <vector>
struct A {
int a;
int x;
};
int main() {
using namespace std;
A a1;
A a2;
vector<A> va;
va.push_back(a1);
va.push_back(move(a2));
}
Run Code Online (Sandbox Code Playgroud)
我知道std :: vector的元素是连续存储的,与std :: list不同.在上面的代码a2被移动但是真的没有复制a2到向量va?va.push_back(a2);和之间有什么区别va.push_back(move(a2));?
当我设计类接口时,我坐在那里思考是否应该使用const char*或const std::string&经常使用它,当它归结为它时,我常常觉得一只手中有6只,另一只手拿着半打.
采用以下两个函数原型:
void foo(const char* str);
void foo(std::string str);
Run Code Online (Sandbox Code Playgroud)
如果foo函数是存储字符串,我会说第二个是更好的选择,因为能够传递字符串并尽可能利用移动语义.但是,如果foo只需要读取字符串,const char*解决方案会更好吗?
从性能角度来看,std::string不需要创建临时的.但是,使用已经存在的字符串作为参数调用该函数看起来很突出:foo(mystr.c_str()).更糟糕的是,如果需要在未来的某个时刻对阵列进行更高级的操作,或者如果应该存储副本,则接口必须进行更改.
所以我的问题是:
是否有明确的定义,无论是个人的还是其他的,约定何时std::string或是const char*更好的选择?此外,在开始一个新项目时,最好是与使用保持一致,还是只考虑最适合当前代码块的哪一个?
据我所知,添加移动语义的目的之一是通过调用特殊构造函数来复制"临时"对象来优化代码.例如,在这个答案中我们看到它可以用来优化这些string a = x + y东西.因为x + y是一个rvalue表达式,所以我们只能复制指向字符串的指针和字符串的大小,而不是深度复制.但正如我们所知,现代编译器支持返回值优化,因此不使用移动语义,我们的代码根本不会调用复制构造函数.
为了证明这一点,我写了这段代码:
#include <iostream>
struct stuff
{
int x;
stuff(int x_):x(x_){}
stuff(const stuff & g):x(g.x)
{
std::cout<<"copy"<<std::endl;
}
};
stuff operator+(const stuff& lhs,const stuff& rhs)
{
stuff g(lhs.x+rhs.x);
return g;
}
int main()
{
stuff a(5),b(7);
stuff c = a+b;
}
Run Code Online (Sandbox Code Playgroud)
在VC++ 2010中执行它并在优化模式下执行g ++后,我得到空输出.
它是什么样的优化,如果没有它,我的代码仍然可以更快地运行?你能解释一下我的理解错误吗?
我知道c ++中的以下情况,其中将调用复制构造函数:
当为现有对象分配其自己的类的对象时
MyClass A,B;
A = new MyClass();
B=A; //copy constructor called
Run Code Online (Sandbox Code Playgroud)如果函数接收作为参数,按值传递,则为类的对象
void foo(MyClass a);
foo(a); //copy constructor invoked
Run Code Online (Sandbox Code Playgroud)当函数返回(按值)类的对象时
MyClass foo ()
{
MyClass temp;
....
return temp; //copy constructor called
}
Run Code Online (Sandbox Code Playgroud)请随时纠正我所犯的任何错误; 但是如果有任何其他情况需要调用复制构造函数,我会更好奇.
考虑以下代码:
#include <iostream>
using namespace std;
void Func(int&& i) {
++i;
}
int main() {
int num = 1234;
cout << "Before: " << num << endl;
Func(std::move(num));
cout << "After: " << num << endl;
}
Run Code Online (Sandbox Code Playgroud)
它的输出是:
Before: 1234
After: 1235
Run Code Online (Sandbox Code Playgroud)
显然,i正在内部进行修改Func,因为它i在被"转换"为r值引用之后被绑定到参数std::move.
好吧,我的观点:
移动对象意味着将资源的所有权从一个对象转移到另一个对象.但是,内置类型不包含资源,因为它们本身就是资源.转移他们持有的资源毫无意义.如示例所示,num修改了s值.它的资源,它的自我,是被修改的资源.
内置类型有移动语义吗?
另外,内置类型对象在移动后(如果是)是一个明确定义的行为吗?
有人可以向R-Value解释或指出某种解释吗?我不确定它是什么,我的项目必须加入它.下面是R-Value的演示(第一部分是r_string.hpp):
#include <algorithm>
#include <iostream>
template <typename CHAR_T = char>
class basic_rstring {
public:
typedef CHAR_T value_type;
typedef CHAR_T* pointer_type;
typedef CHAR_T const* pointer_const_type;
private:
pointer_type _data;
std::size_t _length;
public:
basic_rstring() : _data(nullptr), _length(0)
{
std::cout << "Default ctor\n";
}
basic_rstring( pointer_const_type s )
: _data( nullptr )
, _length( 0 )
{
std::cout << "Literal ctor: " << s << std::endl;
_length = strlen( s );
_data = new value_type[ _length + 1 ];
std::copy( s, s + _length …Run Code Online (Sandbox Code Playgroud) 我很困惑何时调用移动构造函数与复制构造函数.我已经阅读了以下资料:
所有这些来源要么过于复杂(我只想要一个简单的例子),要么只展示如何编写移动构造函数,而不是如何调用它.我写了一个简单的问题更具体:
const class noConstruct{}NoConstruct;
class a
{
private:
int *Array;
public:
a();
a(noConstruct);
a(const a&);
a& operator=(const a&);
a(a&&);
a& operator=(a&&);
~a();
};
a::a()
{
Array=new int[5]{1,2,3,4,5};
}
a::a(noConstruct Parameter)
{
Array=nullptr;
}
a::a(const a& Old): Array(Old.Array)
{
}
a& a::operator=(const a&Old)
{
delete[] Array;
Array=new int[5];
for (int i=0;i!=5;i++)
{
Array[i]=Old.Array[i];
}
return *this;
}
a::a(a&&Old)
{
Array=Old.Array;
Old.Array=nullptr;
}
a& a::operator=(a&&Old)
{
Array=Old.Array;
Old.Array=nullptr;
return *this;
}
a::~a()
{
delete[] Array;
} …Run Code Online (Sandbox Code Playgroud) 现在我用下面的一段代码dummily转换基本类型(int,long,char[],这种东西),以std::string进行进一步的处理:
template<class T>
constexpr std::string stringify(const T& t)
{
std::stringstream ss;
ss << t;
return ss.str();
}
Run Code Online (Sandbox Code Playgroud)
但是我不喜欢它依赖的事实std::stringstream.我尝试使用std::to_string(来自C++ 11的保留节目)然而它会扼杀char[]变量.
有一种简单的方法可以为这个问题提供优雅的解决方案吗?