auto em C++Em C++, a palavra-chave auto é um recurso poderoso introduzido no C++11, usada para declarar variáveis com um tipo de dado inferido.
O compilador deduz o tipo da variável a partir do seu inicializador, o que pode deixar o código mais legível e mais fácil de manter.
Considere o exemplo a seguir, em que auto é usada para declarar variáveis:
auto dragon_population{3}; // dragon_population is deduced as an integer
auto westeros{7.7777}; // westeros is deduced as a double
auto wedding_location{"The Twins"}; // wedding_location is deduced as a const char*, not std::string
Em cada caso, o tipo da variável é inferido a partir do valor com o qual ela é inicializada.
A palavra-chave auto ajuda a escrever código mais conciso e legível, reduzindo a verbosidade dos tipos explícitos.
const std::vector<std::string> pigeon_pie{"flour", "butter", "pigeon", "salt"};
auto purple_wedding_pie{pigeon_pie};
purple_wedding_pie.emplace_back("the strangler");
Neste laço, auto deduz o tipo de purple_wedding_pie como std::vector<std::string>, evitando a necessidade de especificar o tipo novamente de forma explícita.
A palavra-chave auto é compatível com diversas construções de C++, o que a torna uma ferramenta versátil na programação moderna em C++.
auto& element{array[0]}; // reference to an element
const auto object{otherObject}; // const type version of otherObject's type
auto* ptr{&x}; // pointer to x with the same type as x, but as a pointer.
Em conceitos posteriores, veremos com frequência a palavra-chave auto com expressões lambda, laços for baseados em intervalo e iteradores.
Ponteiros inteligentes são um recurso moderno do C++ criado para oferecer gerenciamento automático de memória, ajudando a evitar vazamentos de memória e ponteiros pendentes, problemas comuns associados a ponteiros brutos. Eles funcionam como wrappers em torno de ponteiros brutos, acrescentando funcionalidades extras, como a liberação automática da memória quando o ponteiro não é mais necessário.
Ponteiros inteligentes geralmente são implementados como templates de classe na biblioteca padrão do C++.
Os dois ponteiros inteligentes mais usados são std::unique_ptr e std::shared_ptr.
std::unique_ptr é um ponteiro inteligente que possui o objeto com exclusividade.
Ele garante que, a qualquer momento, apenas um objeto std::unique_ptr seja dono do recurso.
Quando o std::unique_ptr proprietário é destruído ou reiniciado, ele destrói automaticamente os objetos e libera sua memória.
#include <memory>
// Declaring and defining a unique pointer
auto rightful_king_of_england = std::make_unique<std::string>("Excalibur");
// Unique pointers cannot be copied or assigned
auto mordred = rightful_king_of_england; // Error: Cannot copy a unique_ptr
std::make_unique()
Ao criar um std::unique_ptr, é preferível usar std::make_unique() em vez de usar new diretamente para alocar memória.
std::make_unique() oferece várias vantagens:
std::make_unique() garante segurança de exceções.
Se uma exceção for lançada durante a construção do objeto, a memória será liberada automaticamente, evitando vazamentos de memória.std::make_unique() deixa o código mais claro e mais conciso.
Elimina a necessidade de especificar explicitamente o tipo que está sendo alocado, já que os argumentos de template são deduzidos automaticamente.std::make_unique() de forma mais eficaz do que alocando memória manualmente com new, o que pode resultar em melhor desempenho.std::unique_ptr é construído manualmente.
Isso levaria a um comportamento indefinido quando o std::unique_ptr tenta excluí-lo ao final do seu escopo.std::shared_ptr é um ponteiro inteligente que permite que vários objetos std::shared_ptr compartilhem a propriedade do mesmo recurso.
Ele acompanha quantos ponteiros compartilhados estão referenciando o recurso e libera a memória apenas quando o último ponteiro compartilhado que possui o recurso sai de escopo ou é reiniciado.
// Declaring and defining a shared pointer to a dynamically allocated string
auto martian_congressional_republic = std::make_shared<std::string>("protomolecule");
// Creating more shared pointer that shares ownership
auto outer_planets_alliance = martian_congressional_republic;
auto united_nations = martian_congressional_republic;
No C++17 e anteriores, usar std::shared_ptr com arrays via std::make_shared<T[]> não é suportado diretamente.
Embora seja possível alocar arrays com std::make_shared<T[]>, criar ponteiros compartilhados diretamente a partir deles pode levar a um comportamento indefinido, devido a diferenças no gerenciamento de memória entre objetos únicos e arrays.
Em vez disso, considere usar std::vector ou funções de exclusão personalizadas para gerenciar arrays com ponteiros compartilhados de forma eficaz.
Sempre garanta a compatibilidade com seu compilador e com a implementação da biblioteca padrão ao lidar com alocação de arrays e ponteiros compartilhados no C++17.
std::make_shared()
Assim como std::make_unique(), std::make_shared() oferece benefícios como maior eficiência de memória, segurança de exceções e legibilidade.
Ela combina a alocação de memória para o bloco de controle e para o objeto gerenciado em uma única operação, melhorando a eficiência e reduzindo o risco de vazamentos de memória.
Além disso, a dedução automática dos argumentos de template simplifica o código e melhora a legibilidade.
Usar std::make_shared() promove um código mais limpo, mais seguro e mais eficiente ao trabalhar com objetos std::shared_ptr em C++.
Use ponteiros inteligentes por padrão: std::unique_ptr para propriedade exclusiva e std::shared_ptr para propriedade compartilhada.
Reserve ponteiros brutos para referências não proprietárias ou para interagir com código legado.
Na maioria dos casos, std::unique_ptr é suficiente para propriedade exclusiva, pois oferece um gerenciamento de memória leve, sem a sobrecarga da contagem de referências.
std::shared_ptr deve ser usado com moderação, pois introduz sobrecarga e complexidade, a menos que a propriedade compartilhada de fato seja necessária.
Este exercício leva você ao mundo de Troia. A vida de seu povo é cheia de maravilhas e magia. Muitos humanos em Troia possuem poderes, que são usados com frequência em seu dia a dia. Os poderes são usados para remodelar o mundo ou influenciar a fauna de Troia e outras pessoas. A magia também se manifesta em artefatos únicos, muito cobiçados por aventureiros, artesãos e sábios.
Neste exercício, você vai escrever código para modelar os humanos de Troia, os artefatos que eles possuem e as interações de poder.
Você tem seis tarefas. A primeira está relacionada a criar um humano; as outras cinco tratam de lidar com poderes e artefatos.
No seu modelo de Troia, os humanos são o elemento mais importante. O humano do seu modelo deve ser capaz de possuir um artefato único. Ele também deve ter a capacidade de manifestar um poder. Esses poderes podem afetar outros humanos, então você também quer modelar se um humano é influenciado por algum outro poder.
Você recebe implementações básicas das structs artifact e power.
Implemente uma struct (ou classe) human que tenha um smart-pointer para uma variável membro artifact chamada possession.
Cada artefato só pode ser possuído por um único humano de cada vez.
Um human deve ter duas variáveis membro adicionais.
Uma guarda o own_power e a outra é um poder que o influencia, o influenced_by.
Tanto own_power quanto influenced_by são smart-pointers para powers.
Cada power pode pertencer a um único humano, mas também influenciar outros humanos ao mesmo tempo.
Por padrão, os humanos nascem sem nenhum artefato, não possuem poderes e também não são influenciados por nenhum.
human mindy_mccready{};
mindy_mccready.possession;
// => nullptr
mindy_mccready.own_power;
// => nullptr
mindy_mccready.influenced_by;
// => nullptr
Seu modelo é entediante sem a interação entre suas partes. Você quer criar artefatos únicos e entregá-los a certos humanos.
Defina a função give_new_artifact, que não retorna nada, mas recebe uma referência a um human e uma string.
Com a string, ela deve definir um novo objeto artifact e ajustar o ponteiro possession do human de acordo.
A função não deve retornar nada.
human erik_magnus_lehnsherr{};
give_new_artifact(erik_magnus_lehnsherr, "Mind shielding helmet");
erik_magnus_lehnsherr.possession->name;
// "Mind shielding helmet"
O mundo de Troia gira em torno da interação. Você quer que as pessoas negociem trocando suas posses.
Escreva uma função exchange_artifacts que não retorna nada, mas recebe dois smart-pointers de artefato para trocar os itens.
Lembre-se de que você não pode copiar um unique_ptr.
Isso inclui o uso em parâmetros de função.
Use uma referência ao unique_ptr em vez disso.
human uchiha{};
give_new_artifact(uchiha, "konoha headband");
human uzumaki{};
give_new_artifact(uzumaki, "forehead protector");
exchange_artifacts(uchiha.possession, uzumaki.possession);
uchiha.possession->name;
// "forehead protector"
uzumaki.possession->name;
// "konoha headband"
A característica mais empolgante de Troia são os poderes especiais que as pessoas podem empunhar. Alguns conseguem fundir ferro com o pensamento, enquanto outros curam qualquer ferida instantaneamente durante a noite.
Defina a função manifest_power, que não retorna nada, mas recebe uma referência a um human e uma string.
Com a string, ela deve definir um novo objeto power e ajustar o ponteiro own_power do human de acordo.
A função não deve retornar nada.
human eleven {};
manifest_power(eleven, "psychokinesis");
eleven.own_power->effect;
// "psychokinesis"
De que servem os maiores poderes, se você não pode usá-los? Seu modelo concentra-se nos humanos, então você quer acompanhar a influência dos poderes.
Escreva uma função void use_power que recebe duas referências a humanos.
O primeiro humano é o conjurador e o segundo representa o alvo.
O ponteiro influenced_by do alvo deve apontar para o poder do conjurador.
Por simplicidade, os humanos só podem ser influenciados por um único poder. Esse poder permanece mesmo que o conjurador não exista mais.
human pamela_isley{};
manifest_power(pamela_isley, "control pheromones");
human count_vertigo{};
use_power(pamela_isley, count_vertigo);
count_vertigo.influenced_by->effect;
// "control pheromones"
Certos poderes perdem a potência ou disparam certos efeitos na sua simulação quando são aplicados a vários humanos. Você quer acompanhar o número de pessoas conectadas a cada poder.
Defina a função power_intensity, que recebe um humano e retorna a intensidade do poder dele como um int.
Se a pessoa não tiver poder, o valor de retorno deve ser 0.
Caso contrário, a intensidade deve refletir o conjurador e todas as pessoas influenciadas no momento.
human jean_grey{};
manifest_power(jean_grey, "uplifting personality");
human scott{};
human logan{};
human ororo{};
use_power(jean_grey, ororo);
use_power(jean_grey, logan);
use_power(jean_grey, scott);
power_intensity(jean_grey);
// 4
Crie sua conta no Exercism para aprender e dominar C++ com 19 conceitos100 exercícios e mentoria humana de verdade, tudo de graça.