Pergunta

Um problema de "tipos de valor" com recursos externos (como std::vector<T> ou std::string) é que copiá-los tende a ser bastante caro, e as cópias são criadas implicitamente em vários contextos, de modo que este tende a ser uma preocupação de desempenho.C++0x a resposta para este problema é mover semântica, que é conceptionally baseado na ideia de recurso de furtos e tecnicamente alimentado por referências rvalue.

Não ia ter nada semelhante a mover semântica ou rvalue referências?

Foi útil?

Solução

Eu acredito que há vários lugares em D (tais como o retorno de estruturas) que D consegue fazer com que eles se move enquanto que o C++ gostaria de fazer-lhes uma cópia.IIRC, o compilador irá fazer um movimento, em vez de uma cópia, em qualquer caso, onde ele pode determinar que uma cópia não é necessário, de modo estrutura copiar é que vai acontecer a menos em D do que em C++.E claro, já que as aulas são referências, não tem problema.

Mas, independentemente, de cópia de construção já funciona de forma diferente em D do que em C++.Geralmente, em vez de declarar um construtor de cópia, você declara uma postblit construtor: this(this).Ele faz uma completa memcpy antes this(this) é chamado, e você apenas faça as alterações são necessárias para assegurar que a nova estrutura é separado do original (como fazer uma cópia de profundidade de variáveis de membro onde necessário), em oposição à criação de uma nova construtor que deve cópia de tudo.Assim, a abordagem geral já é um pouco diferente do C++.Também é geralmente concordado que estruturas não devem ter caro postblit construtores de cópia de estruturas deve ser barato, por isso é um problema menor do que seria em C++.Objetos que seria caro para copiar geralmente são classes ou estruturas de referência ou de VACA, semântica.

Recipientes, geralmente, são tipos de referência (em Fobos, eles são estruturas em vez de classes, uma vez que eles não precisam de polimorfismo, mas a cópia não copia seu conteúdo, portanto eles ainda são tipos de referência), para copiá-los em torno não é caro, como seria feito em C++.

Pode muito bem haver casos em D, onde ela poderia usar algo semelhante a uma mudança de construtor, mas, em geral, D foi concebido de tal forma a reduzir os problemas que C++ tem com a cópia de objetos ao seu redor, então é nem de perto o problema que ele está em C++.

Outras dicas

D tem um valor separado e semântica de objetos:

  • Se você declarar seu tipo como struct, terá valor semântico por padrão
  • Se você declarar seu tipo como class, terá um objeto semântico.

Agora, supondo que você não gerencia a memória você mesmo, pois é o caso padrão em D - usando um coletor de lixo - você precisa entender esse objeto de tipos declarados como class são automaticamente ponteiros (ou "referência", se você preferir) ao objeto real, não ao próprio objeto real.

Então, ao passar os vetores em D, o que você passa é a referência/ponteiro. Automaticamente. Nenhuma cópia envolvida (exceto a cópia da referência).

É por isso que D, C#, Java e outros idiomas não "precisam" de mover semântica (como a maioria dos tipos é semântica de objetos e é manipulada por referência, não por cópia).

Talvez eles possam implementá -lo, não tenho certeza. Mas eles realmente receberiam um impulso de desempenho como no C ++? Por natureza, não parece provável.

De alguma forma, tenho a sensação de que, na verdade, as referências de Rvalue e todo o conceito de "semântica de mover" é uma conseqüência de que é normal em C ++ criar objetos de pilha "temporários" locais. Em D e a maioria dos idiomas GC, é mais comum ter objetos na pilha, e então não há despesas gerais com um objeto temporário copiado (ou movido) várias vezes ao devolvê -lo através de uma pilha de chamadas - Portanto, não há necessidade de um mecanismo para evitar essa sobrecarga também.

Em D (e a maioria dos idiomas GC) A class O objeto nunca é copiado implicitamente e você está passando apenas a referência na maioria das vezes, então isso poderia significa que você não precisa de nenhuma referência de RValue para eles.

Otoh, struct Os objetos não devem ser "lidar com os recursos", mas tipos de valor simples se comportando semelhantes aos tipos incorporados - então, novamente, nenhuma razão para qualquer semântica de movimento aqui, IMHO.

Isso renderia uma conclusão - D não tem refs rvalue porque não precisa deles.

No entanto, não usei referências de rvalue na prática, só li sobre elas, então eu poderia ter pulado alguns casos de uso reais desse recurso. Por favor, trate este post como um monte de pensamentos sobre o assunto que, esperançosamente, seria útil para você, não como um julgamento confiável.

Acho que todas as respostas falharam completamente em responder à pergunta original.

Primeiro, como afirmado acima, a questão é relevante apenas para estruturas. As aulas não têm movimento significativo. Também declarado acima, para estruturas, uma certa quantidade de movimento acontecerá automaticamente pelo compilador sob certas condições.

Se você deseja controlar as operações de movimentação, eis o que você precisa fazer. Você pode desativar a cópia anotando isso (isso) com @Disable. Em seguida, você pode substituir C ++ 's constructor(constructor &&that) Definindo this(Struct that). Da mesma forma, você pode substituir o design com opAssign(Struct that). Nos dois casos, você precisa garantir que destrua os valores de that.

Para atribuição, já que você também precisa destruir o valor antigo de this, a maneira mais simples é trocá -los. Uma implementação de C ++ 's unique_ptr portanto, seria algo assim:

struct UniquePtr(T) {
    private T* ptr = null;

    @disable this(this); // This disables both copy construction and opAssign

    // The obvious constructor, destructor and accessor
    this(T* ptr) {
        if(ptr !is null)
            this.ptr = ptr;
    }

    ~this() {
        freeMemory(ptr);
    }

    inout(T)* get() inout {
        return ptr;
    }

    // Move operations
    this(UniquePtr!T that) {
        this.ptr = that.ptr;
        that.ptr = null;
    }

    ref UniquePtr!T opAssign(UniquePtr!T that) { // Notice no "ref" on "that"
        swap(this.ptr, that.ptr); // We change it anyways, because it's a temporary
        return this;
    }
}

Editar: Observe que não defini opAssign(ref UniquePtr!T that). Esse é o operador de atribuição de cópias e, se você tentar defini -lo, o compilador errará porque você declarou, no @disable linha, que você não tem isso.

Eu acho que se você precisar da fonte para perder o recurso, poderá estar com problemas. No entanto, sendo GC'ed, muitas vezes pode evitar a necessidade de se preocupar com vários proprietários, para que não seja um problema para a maioria dos casos.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top