Ссылки на С++ Rvalue и семантику перемещения

У С++ 03 была проблема с ненужными копиями, которые могли бы произойти неявно. Для этой цели в С++ 11 были введены rvalue references и move semantics. Теперь мой вопрос в том, что эта ненужная проблема копирования также существует в таких языках, как С# и java, или это только проблема с С++? Другими словами, rvalue references делает С++ 11 еще более эффективным по сравнению с С# или Java?

Что касается С# (допустимая перегрузка оператора), скажем, у нас есть математический векторный класс, и мы используем его следующим образом.

vector_a = vector_b + vector_c;

Компилятор обязательно преобразует vector_b + vector_c в некоторый временный объект (позволяет называть его vector_tmp).

Теперь я не думаю, что С# может различать временное значение r, например vector_tmp, или lvalue, например vector_b, поэтому нам все равно придется копировать данные на vector_a, чего легко избежать используя rvalue references и move semantics в С++ 11.

Ответ 1

Ссылки на классы в С# и Java имеют некоторые свойства shared_ptr в С++. Однако ссылки rvalue и семантика перемещения относятся скорее к временным типам значений, но типы значений в С# довольно негибкие по сравнению с типами значений С++, и из моего собственного опыта С# вы получите классы, а не структуры, большинство времени.

Итак, мое предположение заключается в том, что ни Java, ни С# не выиграли бы от этих новых возможностей С++, что позволяет сделать безопасные предположения, является ли что-то временным, а вместо копирования позволяет просто украсть контент.

Ответ 2

да ненужная операция копирования есть в С# и java.

ли ссылки rvalue делают С++ 11 еще более эффективным по сравнению с С# или Java?

Ответ - да.:)

Ответ 3

Поскольку классы в Java и С# используют ссылочную семантику, на этих языках никогда не существует неявных копий объектов. Проблема семантики решения проблемы не существует и никогда не существовала в Java и С#.

Ответ 4

Я думаю, что это может произойти в Java. См. Операцию add и add_to ниже. 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);
    }
}

Таким образом, я думаю, что это зависит от того, какую функциональность вы предоставляете пользователю с вашими классами.

Ответ 5

Проблема возникает много. Кто-то я хочу удержать уникальную копию объекта, которую никто другой не может изменить. Как это сделать?

  • Сделайте глубокую копию любого объекта, который кто-то дает мне? Это будет работать, но это не эффективно.
  • Попросите людей дать мне новый объект и не хранить копию? Это быстрее, если вы храбры. Ошибки могут исходить из совершенно несвязанного фрагмента кода, который модифицирует объект через несколько часов.
  • Стиль С++: переместите все элементы из ввода в мой собственный новый объект. Если вызывающий абонент случайно попытается снова использовать объект, он сразу увидит проблему.
  • Иногда может помочь сборка только для чтения на С#. Но в моем опыте, как правило, боль в лучшем случае.

Вот что я говорю:

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);
    }
}

Этот вопрос лежит в основе Clojure и других функциональных языков!

В общем, да, мне часто жаль, что у меня не было структур и данных типа С++ 11 в С#.

Ответ 6

Вы можете попробовать эмулировать семантику перемещения. Например, в примере 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> methods by calling Map 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;
        }
    }
}