Pergunta

Um dos C ++ 0x melhorias que permitirão a escrever mais eficiente código C ++ é o ponteiro inteligente unique_ptr (muito ruim, que não vai permitir que se deslocam através memmove () como operações: a proposta não fez para o draft).

Quais são outras melhorias de desempenho no próximo padrão Tome seguinte código por exemplo:?

vector<char *> v(10,"astring");
string concat = accumulate(v.begin(),v.end(), string(""));

O código irá concatenar todas as cordas contido no vector v . O problema com esta peça elegante de código é que se acumulam () copia as coisas ao redor, e não usa referências. E a string () realoca cada vez mais operador é chamado. O código tem, portanto, um fraco desempenho em comparação com o código C analógico bem optimizada.

O C ++ 0x fornecer ferramentas para resolver o problema e talvez outros?

Foi útil?

Solução

resolve Sim C ++ o problema através de algo chamado Mover semântica .

Basicamente, ele permite a um objeto para assumir a representação interna de outro objeto se o objeto é um temporário. Em vez de copiar cada byte na seqüência através de uma cópia-construtor, por exemplo, muitas vezes você pode apenas permitir que a string de destino para assumir a representação interna da cadeia fonte. Isso é permitido apenas quando a fonte é um valor de r.

Isto é feito através da introdução de um movimento construtor . É um construtor onde você sabe que o objeto src é uma temporária e está indo embora. Por isso, é aceitável para o destino para assumir a representação interna do objeto src.

O mesmo é verdadeiro para operadores movimento de atribuição .

Para distinguir um construtor de cópia de um construtor movimento, a linguagem introduziu referências rvalue . A classe define seu construtor movimento para tomar um referência rvalue , que só será obrigado a rvalues ??(temporários). Assim, a minha classe definiria algo ao longo das linhas de:

 class CMyString
 {
 private:
     char* rawStr;
 public:

     // move constructor bound to rvalues
     CMyString(CMyString&& srcStr) 
     {
         rawStr = srcStr.rawStr
         srcStr.rawStr = NULL;             
     }

     // move assignment operator 
     CMyString& operator=(CMyString&& srcStr) 
     {
         if(rawStr != srcStr.rawStr) // protect against self assignment
         {
             delete[] rawStr;
             rawStr = srcStr.rawStr
             srcStr.rawStr = NULL;
         }
         return *this;
     }

     ~CMyString()
     {
         delete [] rawStr;
     }
 }

Aqui é um artigo muito bom e detalhadas sobre semântica mover ea sintaxe que permite que você faça isso.

Outras dicas

Um desempenho-boost será generalizada expressões constantes, que é introduzido pela palavra-chave constexpr.

constexpr int returnSomething() {return 40;}

int avalue[returnSomething() + 2]; 

Este não é legal C ++ código, porque returnSomething () + 2 não é uma expressão constante.

Mas usando a constexpr palavra-chave, C ++ 0x pode dizer ao compilador que a expressão é uma constante de tempo de compilação.

Desculpe - você não pode Estado como um fato que string concat = accumulate(v.begin(),v.end(), string("")); deve realocar. A vontade implementação direta, é claro. Mas compiladores são muito autorizados a fazer a coisa certa aqui.

Este já é o caso em C ++ 98 e C ++ 0x continua a permitir que ambas as implementações inteligentes e mudos. Dito isto, movimento semântica fará implementações inteligentes mais simples.

vector<string> v(10, "foo");
string concat = accumulate(v.begin(), v.end(), string(""));

Este exemplo é simplesmente má programação, em qualquer C ++ padrão. É equivalente a esta:

string tmp;
tmp = tmp + "foo"; //copy tmp, append "foo", then copy the result back into tmp
tmp = tmp + "foo"; //copy tmp, append "foo", then copy the result back into tmp
tmp = tmp + "foo"; //copy tmp, append "foo", then copy the result back into tmp
tmp = tmp + "foo"; //copy tmp, append "foo", then copy the result back into tmp
tmp = tmp + "foo"; //copy tmp, append "foo", then copy the result back into tmp
tmp = tmp + "foo"; //copy tmp, append "foo", then copy the result back into tmp
tmp = tmp + "foo"; //copy tmp, append "foo", then copy the result back into tmp
tmp = tmp + "foo"; //copy tmp, append "foo", then copy the result back into tmp
tmp = tmp + "foo"; //copy tmp, append "foo", then copy the result back into tmp
tmp = tmp + "foo"; //copy tmp, append "foo", then copy the result back into tmp

C ++ 11 mover semântica só vai cuidar do "copiar parte de trás resultado em tmp" parte da equação. As cópias iniciais de tmp ainda será cópias. É um Schlemiel do pintor algoritmo , mas ainda pior do que o exemplo de costume usando strcat em C.

Se accumulate apenas += vez de + e = usado, então ele teria evitado todas essas cópias.

Mas C ++ 11 nos dá uma maneira de fazer melhor, mantendo-se sucinta, usando uma função lambda:

string concat;
for_each(v.begin(), v.end(), [&](const string &s){ concat += s; });

EDIT: Acho que um implementador biblioteca padrão pode optar por implementar accumulate com o movimento no operando a +, então tmp = tmp + "foo" se tornaria tmp = move(tmp) + "foo", e que seria muito bonito resolver este problema. Eu não tenho certeza se tal implementação seria rigorosamente em conformidade. Nem GCC, MSVC, nem LLVM atualmente faz isso. E como accumulate é definida em <numeric> pode-se supor que só é projetado para uso com tipos numéricos.

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