Ссылки на С++ 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;
}
}
}