C# C++;右值引用和移动语义

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

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
转换为某个临时对象(我们称之为
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++也可以使用引用语义。