C ++ Rvalue ссылки и семантика перемещения - PullRequest
11 голосов
/ 29 февраля 2012

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

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

vector_a = vector_b + vector_c;

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

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

Ответы [ 6 ]

7 голосов
/ 29 февраля 2012

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

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

5 голосов
/ 29 февраля 2012

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

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

ответ - да.:)

4 голосов
/ 29 февраля 2012

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

1 голос
/ 29 апреля 2013

Я думаю, это может произойти в 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);
    }
}

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

0 голосов
/ 21 февраля 2017

Вы можете попытаться эмулировать семантику перемещения. Например, в примере 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;
        }
    }
}
0 голосов
/ 07 сентября 2016

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

  1. Сделать глубокую копию того, что мне кто-то дает?Это бы сработало, но неэффективно.
  2. Попросить людей дать мне новый объект, а не хранить копию?Это быстрее, если ты смелый.Ошибки могут исходить из совершенно не связанного фрагмента кода, модифицирующего объект через несколько часов.
  3. Стиль C ++: переместить все элементы из ввода в мой новый новый объект.Если вызывающий случайно попытается использовать объект снова, он сразу увидит проблему.
  4. Иногда может помочь коллекция только для чтения на 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);
    }
}

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...