2012-02-29 14 views
10

C++ 03 tuvo el problema de copias innecesarias que podrían ocurrir implícitamente. Para este propósito, C++ 11 introdujo rvalue references y move semantics. Ahora mi pregunta es, ¿este problema de copia innecesaria también existe en idiomas como C# y Java o fue solo un problema de C++? En otras palabras, ¿el rvalue references hace que C++ 11 sea aún más eficiente en comparación con C# o Java?C++ Referencias de valores R y semánticas de movimiento

En lo que se refiere a C# (la sobrecarga del operador lo permite), digamos que tenemos una clase vectorial matemática, y la usamos así.

vector_a = vector_b + vector_c; 

El compilador seguramente transformar vector_b + vector_c a algún objeto temporal (le llaman vector_tmp).

Ahora no creo que C# es capaz de diferenciar entre un rvalue temporal como vector_tmp o un valor-I como vector_b, por lo que tendremos que copiar datos a vector_a de todos modos, que puede ser fácilmente evitado mediante el uso rvalue references y move semantics en C++ 11.

+3

no utilice etiquetas de idioma que no están relacionados –

Respuesta

5

si operación de copia innecesaria hay en C# y java.

¿las referencias de rvalue hacen que C++ 11 sea aún más eficiente en comparación con C# o Java?

respuesta es sí. :)

+3

¿Cuándo quiere decir que se produce en Java? Por favor, brinde un ejemplo. Puede ocurrir en implementaciones específicas llamando clonar etc., pero eso parece estar al lado del punto. Java no tiene constructores de copia predeterminados ni copias implícitas, ya que pasó las referencias a los objetos por defecto (en realidad, por valor). –

+0

Sebastian Olsson: Aparentemente las referencias rvalue no tienen nada que ver con los constructores de copia. Tiene que ver con los valores de temperory. ¿Cómo maneja eso C#? Me refiero a cómo maneja la copia de objetos temporales. Por ejemplo, tiene una clase con operaciones sobrecargadas y tiene esta expresión a = b + c + d. ¿Cómo lo maneja C++ y C# de manera diferente? Supongamos que las referencias de uso de implementación de C++. – MetallicPriest

+0

Se trata de una construcción de destrucción innecesaria. Mi punto fue que Java no infiere la creación de objetos de la forma en que lo hace C++. No me atrevo a responder sobre la sobrecarga del operador en C#, ya que no es mi área de especialización. –

4

Como las clases en Java y C# usan semántica de referencia, nunca hay copias implícitas de los objetos en esos idiomas. El problema que la semántica de la resolución de problemas no tiene y nunca ha existido en Java y C#.

+1

C++ también puede usar semántica de referencia. De hecho, los constructores de copia casi siempre se escriben de manera que tomen referencias constantes. Entonces, el problema no parece hacer nada con las referencias. – MetallicPriest

+10

"Pasando por referencia" y "semántica de referencia" son dos cosas diferentes. – fredoverflow

+0

¿Cuál es la diferencia? – MetallicPriest

7

Las referencias de clase en C# y Java tienen algunas propiedades de shared_ptr s en C++. Sin embargo, las referencias rvalue y la semántica de movimiento se relacionan más con tipos de valores temporales, pero los tipos de valores en C# son bastante flexibles en comparación con los tipos de valores C++, y desde mi propia experiencia C#, terminarás con clases, no estructuras, la mayoría del tiempo.

Mi hipótesis es que ni Java ni C# se beneficiarían mucho de las nuevas características de C++, lo que permite al código hacer suposiciones seguras de si algo es temporal y en lugar de copiar permite robar el contenido.

1

Creo que podría ocurrir en Java. Vea la operación add y add_to a continuación. add crea un objeto de resultado para mantener el resultado de la operación de adición de matriz, mientras que add_to simplemente agrega el rhs a esto.

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

Por lo tanto, creo que depende del tipo de funcionalidad que proporcione al usuario con sus clases.

0

El problema surge mucho. Alguien a quien quiero aferrarme a una copia única de un objeto que nadie más puede modificar. ¿Cómo puedo hacer eso?

  1. ¿Hacer una copia profunda de cualquier objeto que alguien me dé? Eso funcionaría, pero no es eficiente.
  2. Pida a las personas que me den un objeto nuevo y que no conserven una copia? Eso es más rápido si eres valiente. Los errores pueden provenir de una pieza de código que no está relacionada y que modifica el objeto horas después.
  3. Estilo C++: mueva todos los elementos de la entrada a mi propio objeto nuevo. Si la persona que llama accidentalmente intenta usar el objeto nuevamente, inmediatamente verá el problema.
  4. A veces, una recopilación de solo lectura C# puede ayudar. Pero en mi experiencia, eso generalmente es un dolor en el mejor de los casos.

Aquí es lo que estoy hablando:

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

Esta pregunta está en el corazón de Clojure y otros lenguajes funcionales!

En resumen, sí, a menudo me gustaría tener C++ 11 estructuras de datos de estilo y operaciones en C#.

0

Puede intentar emular la semántica del movimiento. Por ejemplo en el ejemplo del Comercio-ideas de Philip se puede pasar a medida MovableDictionary en lugar de 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; 
     } 
    } 
} 
Cuestiones relacionadas