C# C++;右值引用和移动语义
C++03存在可能隐式发生的不必要副本的问题。为此,C++11引入了C# C++;右值引用和移动语义,c#,java,c++,c++11,C#,Java,C++,C++11,C++03存在可能隐式发生的不必要副本的问题。为此,C++11引入了rvalue引用和move语义。现在我的问题是,这种不必要的复制问题是否也存在于C++语言和java语言中,或者仅仅是C++问题?换句话说,rvalue引用是否使C++11比C#或Java更高效 就C#而言(其中允许运算符重载),假设我们有一个数学向量类,我们这样使用它 vector_a = vector_b + vector_c; 编译器肯定会将vector\u b+vector\u c转换为某个临时对象(我们称之为vect
rvalue引用
和move语义
。现在我的问题是,这种不必要的复制问题是否也存在于C++语言和java语言中,或者仅仅是C++问题?换句话说,rvalue引用
是否使C++11比C#或Java更高效
就C#而言(其中允许运算符重载),假设我们有一个数学向量类,我们这样使用它
vector_a = vector_b + vector_c;
编译器肯定会将vector\u b+vector\u c
转换为某个临时对象(我们称之为vector\u tmp
)
现在我认为C#无法区分临时右值(如
vector_tmp
)或左值(如vector_b
),因此我们必须将数据复制到vector_a
),在C++11中使用右值引用
和移动语义
可以很容易地避免这种情况。是的,在C#和java中存在不必要的复制操作
右值引用是否使C++11比C#或Java更高效
答案是肯定的 因为Java和C#中的类使用引用语义,所以这些语言中从来没有对象的隐式副本。在C++和java中,问题迁移语义求解不存在也不存在。C++和Java中的类引用具有C++中的代码> SyddYPPTR < /代码>的一些属性。但是,RValk引用和MyStand语义更多地与临时值类型相关,但是C语言中的值类型与C++值类型相比是非常不灵活的,并且从我自己的C语言经验来看,大多数情况下,最终都是类,而不是结构。
我的假设是java和C++都不会从这些新的C++特性中获益,这使得代码能够安全地假设某个事物是临时的,而不是复制,让它只是窃取内容。
< P>我认为它可能发生在java中。请参阅下面的“添加”和“添加到”操作。add创建一个result对象来保存矩阵add操作的结果,而add_to仅将rhs添加到该对象中class Matrix {
public static final int w = 2;
public static final int h = 2;
public float [] data;
Matrix(float v)
{
data = new float[w*h];
for(int i=0; i<w*h; ++i)
{ data[i] = v; }
}
// Creates a new Matrix by adding this and rhs
public Matrix add(Matrix rhs)
{
Main result = new Main(0.0f);
for(int i=0; i<w*h; ++i)
{ result.data[i] = this.data[i] + rhs.data[i]; }
return result;
}
// Just adds the values in rhs to this
public Main add_to(Main rhs)
{
for(int i=0; i<w*h; ++i)
{ this.data[i] += rhs.data[i]; }
return this;
}
public static void main(String [] args)
{
Matrix m = new Matrix(0.0f);
Matrix n = new Matrix(1.0f);
Matrix o = new Matrix(1.0f);
// Chaining these ops would modify m
// Matrix result = m.add_to(n).subtract_from(o);
m.add_to(n); // Adds n to m
m.subtract_from(o); // Subtract o from n
// Can chain ops without modifying m,
// but temps created to hold results from each step
Matrix result = m.add(n).subtract(o);
}
}
类矩阵{
公共静态最终int w=2;
公共静态最终int h=2;
公开数据;
矩阵(浮点v)
{
数据=新浮点数[w*h];
对于(int i=0;i问题经常出现。我想让某人保留一个其他人无法修改的对象的唯一副本。我该怎么做
把别人给我的东西做一个深拷贝?那会有用的,但效率不高
要求人们给我一个新对象,不要保留副本?如果你勇敢的话,这会更快。错误可能来自于几个小时后修改对象的一段完全无关的代码
C++风格:将所有项目从输入移动到我自己的新对象。如果调用方不小心再次尝试使用该对象,他将立即看到问题
有时候,C#只读收藏会有所帮助。但根据我的经验,这通常是一种痛苦
下面是我要说的:
class LongLivedObject
{
private Dictionary <string, string> _settings;
public LongLivedObject(Dictionary <string, string> settings)
{ // In C# this always duplicates the data structure and takes O(n) time.
// C++ will automatically try to decide if it could do a swap instead.
// C++ always lets you explicitly say you want to do the swap.
_settings = new Dictionary <string, string>(settings);
}
}
类LongLivedObject
{
专用词典设置;
公共LongLivedObject(字典设置)
{//在C#中,这总是重复数据结构,并且需要O(n)个时间。
//C++将自动决定是否可以进行交换。
//C++总是让你明确地说你想做交换。
_设置=新词典(设置);
}
}
这个问题是Clojure和其他函数式语言的核心
总之,是的,我经常希望在C#中有C++11风格的数据结构和操作。您可以尝试模拟移动语义。例如,在Trade Ideas Philip的示例中,您可以传递自定义MovableDictionary
,而不是Dictionary
:
public class MovableDictionary<K, V> // : IDictionary<K, V>, IReadOnlyDictionary<K, V>...
{
private Dictionary<K, V> _map;
// Implement all Dictionary<T>'s methods by calling Map's ones.
public Dictionary<K, V> Move()
{
var result = Map;
_map = null;
return result;
}
private Dictionary<K, V> Map
{
get
{
if (_map == null)
_map = new Dictionary<K, V>();
return _map;
}
}
}
public-class-MovableDictionary/:IDictionary,iRadonlyDictionary。。。
{
私人字典(地图),;
//通过调用Map的方法来实现所有Dictionary的方法。
公共字典移动()
{
var结果=Map;
_map=null;
返回结果;
}
专用字典地图
{
得到
{
如果(_map==null)
_map=新字典();
返回图;
}
}
}
您什么时候认为它出现在Java中?请提供一个示例。它可以出现在调用clone等的特定实现中,但这似乎离题了。Java没有默认的副本构造函数和隐式副本,因为它在默认情况下(实际上是按值)传递对对象的引用Sebastian Olsson:显然R值引用与复制构造函数无关。它与温度ravs有关。C是如何处理这个?我是指它如何处理临时对象的复制。例如,您有一个重载操作的类,并且您有这个表达式a= b+c+d。C++和C是如何处理它的?假设C++实现使用引用。它是一个不必要的破坏结构。我的意思是java不以C++的方式推断对象创建。我不敢回答C语言中操作符重载的问题,因为它不是我的专长领域。塞巴斯蒂安:我明白你的意思。你是说java没有拷贝构造函数,这个问题在Java.Well.几乎不存在。我的意思是,由于Java不会使用复制构造函数通过自动对象复制传递值,而是通过引用对象的值传递值,所以不会发生这种情况。如果Java自动调用深度克隆()当通过一个对象时,它将是一个问题。如果你用一个不可变的方法模拟操作符重载,比如A+AdAd(B.Add(C)),如果Advad创建一个新对象,但是在爪哇中没有这样的默认行为,C++的一部分可以发生在java中的特定实现中。C++也可以使用引用语义。