Declarando variáveis atrás do laço ou dentro do laço? - página 11

 
Vict:

Eu procurei, e descobri que nenhum compilador https://en.cppreference.com/w/cpp/compiler_support terminou os módulos, então não há nada para ver.

Ainda conseguiu utilizar os módulos via clang

// module
export module M;
export int f(int x) {
    return 2 + x;
}

// main.cc
import M;
int main() {
        for(int i = 0;  i < 1000000;  ++ i)
                f(5);
}

Compilado com otimização, o loop não foi executado (ou seja, a otimização é realizada entre: unidade de tradução + módulos meio conectados, ao invés de apenas uma unidade de tradução como antes). Sem nenhum LTO. std c++ candidato se move inteiramente para módulos, imho, e não haverá perguntas: "por que tão lento neste exemplo artificial com loop nú".

 
Alexey Navoykov:

Portanto, parece ter descoberto que ele aloca e apaga a memória toda vez, mesmo neste caso:


A propósito, posso ter dado resultados errados da última vez. O mais provável foi no modo x86. Agora estou testando no modo x64 e os resultados por C++ são muito melhores:

1) ~ 2000 msec

2) ~ 200 ms (é 3 vezes mais rápido).

Embora eu também tenha atualizado o Studio para a versão mais recente, ele também deve ter influenciado, já que até o x86 é mais rápido agora do que os testes anteriores.

Bem, agora C++ não é tão vergonhosamente perdido para Sharp. apenas por 3 vezes aproximadamente )

Hmm, então não há coletor de lixo, qual é a questão da definição?

Não estou falando de velocidade, estou falando de memória
 
Alexey Navoykov , acontece que a corda e o vetor do constexpr foram arrastados para c++20. Isto é, todos os nossos testes não aceitarão uma única instrução para servir um fio, por exemplo, alocar memória, etc. (bem, se os símbolos não vierem desde cedo, é claro). Legal.
 
Vict:
Alexey Navoykov , acontece que a corda e o vetor constexpr foram arrastados para C++20. Isto é, todos estes testes não aceitarão uma única instrução para manutenção de cordas, por exemplo, alocar memória, etc. (bem, se os símbolos não vierem desde cedo, é claro). Legal.

É necessário marcar tudo explicitamente como constexpr ou ele irá detectá-lo automaticamente?

A meu ver, o problema não está no padrão, mas no compilador. Algo o impede de cortar coisas desnecessárias agora? Especialmente estranho que o compilador Sharp otimize normalmente, enquanto a versão plus da mesmaMicrosoft falha. Embora pareça que eles deveriam ter uma base comum (em termos de otimização de tais construções)

 
Alexey Navoykov:

É necessário marcar tudo explicitamente como constexpr ou ele irá detectá-lo automaticamente?

A std é automática, basta que o cordão receba as cordas que são conhecidas em tempo de compilação. Todas as operações (procurar, substituir, ...) por esta cadeia serão as mesmas em tempo de compilação (suspeito que o sharp e o mcl também contaram nossos exemplos em tempo de compilação). O plano é fazer com que todos os recipientes constepxr. Isto é, não depende mais do humor do compilador, mas garantido pelo padrão, podemos calcular o parâmetro do modelo através da análise de strings, por exemplo. Aqui está o que é interessante - acontece que agora também constexpr (para os tipos de constexpr)?

Como me parece, o problema não está no padrão, mas no compilador. Algo o impede de cortar coisas desnecessárias? Especialmente estranho é o fato de que o compilador Sharp otimiza normalmente e a versão plus da mesma Microsoft falha, embora pareça que eles devem ter uma base comum (em termos de otimização de tais construções)

Além disso, tem uma desvantagem em termos de possibilidades de otimização - está apenas dentro de uma unidade de tradução (se não usarmos o LTO). Claro que você pode fazer todo o std em arquivos de cabeçalho, mas eles não (por causa do tempo de compilação?). O Sharp com módulos é mais avançado a este respeito. Mas o c++20 também corrigirá isso em breve com o advento dos módulos. Também planeja mudar a std para lá (primeiro eles depurarão os módulos e depois a escreverão). Mas a VS parece já ter feito std em módulos, você pode tentar (deixe o link acima).

Mas ainda insisto - é melhor declarar após o loop (bem, se não for um tipo fundamental).

 
Alexey Navoykov:

Decidi testá-lo em C# também por curiosidade. Não só os resultados são quase os mesmos em velocidade, mas também funcionam muito mais rápido que C++.

Resultados:

Soma: 894782460, Tempo: 69 ms.

Soma: 894782460, Tempo: 56 ms

E aqui está um análogo em C++:

Soma: 894782460, Tempo: 2947 ms

Soma: 894782460, Tempo: 684 ms

Testei-o no VS 2019.Toda otimização está habilitada .

Parafusar um programa C++).

p.s. Os resultados em C# variam agradavelmente de teste para teste, mas na média, ambas as variantes são igualmente rápidas.

Dica: em corda afiada é do tipo base, em pluses é uma classe escrita em pluses. Na variante Sharpe, a atribuição de cordas é feita uma vez, em pluses - 10e6 vezes. No final, as vantagens são mais rápidas, mas você precisa ser inteligente ao escrever código, não fazer uma corcunda como os índios em Boeing.
 
SeriousRacoon:
Dica: em corda afiada é do tipo base, em pluses é uma classe escrita em pluses. Na variante Sharpe, a atribuição de cordas é feita uma vez, em pluses - 10e6 vezes. As vantagens são mais rápidas no final, mas você precisa ligar seu cérebro ao escrever o código em vez de fazer um corcunda como os índios em Boeing.
Não, não é disso que se trata. Eu simplesmente esqueci que existe uma classe e é a referência que é atribuída, não o objeto em si. Portanto, a comparação é incorreta nesta forma
 

A propósito, por falar em otimização. Você gostaria que o compilador otimizasse algo aqui?

mutex mtx;

void thread_0() {
        while (true) {
                do_task_0();
                {
                        lock_guard<mutex> lck{mtx};
                        do_task_1();
                }
                do_task_2();
                {
                        lock_guard<mutex> lck{mtx};
                        do_task_3();
                }
                do_task_4();
        {
}
void thread_1() {
        while (true) {
                do_task_5();
                {
                        lock_guard<mutex> lck{mtx};
                        do_task_6();
                }
                do_task_7();
                {
                        lock_guard<mutex> lck{mtx};
                        do_task_8();
                }
                do_task_9();
        {
}
 
Alexey Navoykov:
Não, o ponto é bem diferente lá. Acabo de esquecer que a corda é uma classe ali e é uma referência que é atribuída, não o objeto em si. Portanto, a comparação está incorreta nesta forma
Onde a referência (ponteiro) é atribuída? Na seqüência de classes mais? O que você quer dizer com seleção e cópia de buffer ocorrem lá.
 
SeriousRacoon:
Onde a referência (ponteiro) é atribuída? Na seqüência de classes mais? Como assim, é a seleção e cópia de buffer.

ele está falando de afiado