Buscar

Apostila C++11

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 96 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 96 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 96 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

Apostila C++ 11 
 
 
 
 
 
 
 
 
 
Declarações auto 
 
Quando se declara uma variável do tipo auto o compilador irá deduzir o tipo da 
variável através da expressão de inicialização, ou seja, que toda variável de 
tipo auto deve ser inicializada com algum valor, caso contrario teremos erro de 
compilação. 
 
#include <iostream> 
int main() 
{ 
 auto a = 1; 
 auto b = "AGIT"; 
 const auto c = 2; 
 const auto d = "INFORMATICA"; 
 
 vector<string> v1; 
 vector<string>::iterator it = v1.begin(); 
 auto it2 = v1.begin(); 
 
 //auto e; Erro auto não inicializada 
 //const auto f; Erro auto não inicializada 
 
 std::cout << a << '\n' << b << '\n' << c << '\n' << d << '\n'; 
 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
 
 
Laço for baseado em intervalos 
 
 
O Laço for baseado em intervalos é uma nova sintaxe de C++ que nos permite 
percorrer o conteúdo de qualquer container que suporte o conceito de 
intervalos. 
Podemos utiliza-lo em qualquer classe que possa ser acessada através das 
funções Begin e end, classes containers da biblioteca padrão e arrays. 
 
#include <iostream> 
#include <list> 
 
using namespace std; 
 
int main() 
{ 
 list<int> li; 
 
 li.push_back(1); 
 li.push_back(2); 
 li.push_back(3); 
 li.push_back(4); 
 li.push_back(5); 
 
 /* 
 Sintaxe anterior para percorrer containners 
 for(list<int>::iterator it = li.begin(); it != li.end(); ++it) 
 cout << *it << '\n'; 
 */ 
 
 //Sintaxe C++ 11 
 for(auto it : li) 
 cout << it << '\n'; 
 /* 
 Ou com referencia 
 for(auto &it : li) 
 cout << it << '\n'; 
 */ 
 
 return 0; 
} 
 
Nullptr 
 
Usado para indicar que um ponteiro é nulo, nullptr pode ser convertido para 
qualquer tipo de ponteiro e também para boleano, mas não pode ser usado em 
operações que usam tipos integrais. 
No padrão anterior utilizávamos 0 para indicar que um ponteiro é nulo, mas se 
por exemplo: houvessem duas funções com mesmo nome void teste(int a) e 
void teste(int *a) e quiséssemos chamar void teste(int *a), mas sem passar um 
endereço de outra variável teríamos de chamar teste(0), porem com isso o 
compilador iria se confundir com a outra função teste que recebe um numero 
inteiro e iria chamar a função que não era para ser chamada. 
Com o novo padrão podemos chamar assim: teste(nullptr), isso irá garantir que 
a função que recebe um ponteiro como parâmetro será chamada. 
 
#include <iostream> 
 
using namespace std; 
 
void teste(int a) 
{ 
 cout << "void teste(int a)\n"; 
} 
 
void teste(int *a) 
{ 
 cout << "void teste(int *a)\n"; 
} 
 
int main() 
{ 
 teste(0);//Se confudi com inteiro ao inves de chamar o int *a 
 teste(nullptr);//Garante que void teste(int *a) será chamada 
 return 0; 
} 
 
 
 
 
 
 
 
Enumerações avançadas 
 
Nas enumerações tradicionais o tipo utilizado para armazenar uma 
enumeração é dependente da implementação o que pode nos trazer um gasto 
desnecessário de memória, como por exemplo: vamos criar uma enumeração 
com apenas dois enumeradores um vale 1 e outro vale 2, o tamanho de 1 byte 
seria mais que o suficiente para armazena-los, mas não sabemos se naquele 
ambiente será usado 2, 4, 8, 10 bytes para a enumeração, com isso podemos 
ter um gasto desnecessário de memória. 
As enumerações avançadas nos permite definir qual definir o tamanho da 
enumeração. 
 
#include <iostream> 
 
using namespace std; 
 
enum Frutas 
{ 
 BANANA, 
 PERA 
}; 
 
enum Frutas_ENUM_AVANCADA : char//Dizemos que a enum deverá ocupar 
o tamanho de um char 
{ 
 BANANA_ENUM_AVANCADA, 
 PERA_ENUM_AVANCADA 
}; 
 
int main() 
{ 
 Frutas FR; //Quantos bytes ocupa fruta? 
 cout << sizeof(FR) << '\n'; //No caso dessa maquina 4 bytes 
 
 Frutas_ENUM_AVANCADA FRA; 
 cout << sizeof(FRA) << '\n'; 
 
 return 0; 
} 
 
 
Enumerações com escopo 
 
As enumerações tradicionais possuíam uma serie de problemas como por 
exemplo: enumeradores com mesmo escopo da enumeração, são conversíveis 
para números inteiros, e o tipo utilizado para armazenar o enumerador é 
definido pelo compilador. 
 
#include <iostream> 
 
using namespace std; 
/* 
enum Frutas 
{ 
 BANANA, 
 PERA 
}; 
 
enum Semana 
{ 
 SEGUNDA_FEIRA, 
 TERCA_FEIRA, 
 QUARTA_FEIRA, 
 QUINTA_FEIRA, 
 SEXTA_FEIRA, 
 SABADO, 
 DOMINGO 
}; 
 
 
//PRIMEIRO PROBLEMA 
//Em enumerações tradicionais não podemos ter enumeradores com mesmo 
nome, mesmo que estejam contidos 
//em enumerações diferentes, pois caso houvesse teriamos conflito de nomes e 
erro de compilação. 
enum Frutas_2 
{ 
 BANANA, 
 PERA 
}; 
*/ 
 
//Enumeração com escopo 
enum class Frutas_Com_Escopo : char 
{ 
 BANANA, 
 PERA 
}; 
 
 
enum class Frutas_Com_Escopo_2 : char 
{ 
 BANANA, 
 PERA 
}; 
 
enum class Semana_Com_Escopo : char 
{ 
 SEGUNDA_FEIRA, 
 TERCA_FEIRA, 
 QUARTA_FEIRA, 
 QUINTA_FEIRA, 
 SEXTA_FEIRA, 
 SABADO, 
 DOMINGO 
}; 
 
int main() 
{ 
 //SEGUNDO PROBLEMA 
 //Os enumeradores são conversiveis para inteiro, possibilitando assim que 
existam operações sem 
 //sentido lógico, como no exemplo abaixo. 
 //O que tem haver a pessoa somar um dia da semana com uma fruta???? 
 //cout << DOMINGO + PERA << endl; 
 //Enumerações com escopo 
 //int a = DOMINGO + PERA; Erro, nao pode mais fazer isso. 
 Frutas_Com_Escopo FR; 
 
 FR = Frutas_Com_Escopo::BANANA; 
 //int a = Frutas_Com_Escopo::BANANA; //Erro, agora a conversão deve ser 
explicita. 
 //int a = (int)Frutas_Com_Escopo::BANANA; 
 
 return 0; 
} 
Descobrir o tipo das enumerações 
 
Para se descobrir qual o tipo de dados utilizado por uma enumeração podemos 
utilizar o template std::underlying_type<enum>::type, fazendo-se necessário a 
inclusão do header <type_traits>. 
 
 
#include <iostream> 
#include <type_traits> 
 
using namespace std; 
 
enum Frutas {}; 
enum Semana : char {}; 
 
int main() 
{ 
 cout << boolalpha << is_same<unsigned int, 
underlying_type<Frutas>::type>::value << '\n'; 
 cout << is_same<char, underlying_type<Semana>::type>::value << '\n'; 
 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Declaração posterior de enum 
 
Podemos declarar o protótipo de um enum e declara-lo posteriormente, desde 
que seu tamanho tenha sido definido. 
 
#include <iostream> 
 
using namespace std; 
 
/* 
//Erro 
enum Frutas; 
 
enum Frutas 
{ 
 BANANA, 
 PERA 
}; 
*/ 
//Correto 
enum Frutas : char; 
 
enum Frutas : char 
{ 
 BANANA, 
 PERA 
}; 
 
//Correto (int por padrao) 
enum class Frutas_2; 
 
enum class Frutas_2 
{ 
 BANANA, 
 PERA 
}; 
 
int main() 
{ 
 return 0; 
} 
Suporte a unicode 
 
 
Dois novos tipos foram adicionados para o suporte Unicode char16_t nos 
garante pelo menos 16 bits de tamanho e char32_t nos garante pelo menos 32 
bits. 
Literais para o tipo char16_t e char32_t são definidos prefixando o literal da 
seguinte forma: char16_t c16 = u'A'; e char32_t c32 = U'A'; 
Literaisstring também podem ser usadas na codificação UTF-8 utilizando-se o 
prefixo u8: const char *p = u8"String UTF-8"; 
 
Existem também typedefs para as strings que utilizam codificação diferente: 
 
std::string → std::basic_string<char> 
std::wstring → std::basic_string<wchar> 
std::u16string → std::basic_string<char16_t> 
std::u32string → std::basic_string<char32_t> 
 
 
ã 
#include <iostream> 
 
using namespace std; 
 
int main() 
{ 
 char16_t unicode16 = u'A';//u representa char16_t; 
 char32_t unicode32 = U'a';//u representa char32_t; 
 
 //Literais string u8 
 const char *p = u8"String UTF-8"; 
 
 return 0; 
} 
 
 
 
 
 
 
 
Suporte literais string raw 
 
 
Basicamente uma string raw é uma string onde caracteres como („\n‟, „t‟, „\‟, 
etc...) não são processados. 
Uma string raw inicia com R”(e termina com)”. 
Os delimitadores podem ser personalizados, mas não podem conter espaços 
em branco 
 
#include <iostream> 
 
using namespace std; 
 
int main() 
{ 
 string str = R"(\n)"; 
 string s = R"!!!(ssssss)!!!";//Delimitador personalizado 
 const char16_t *p = uR"(aaa)"; 
 
 cout << str; 
 cout << '\n'; 
 cout << s; 
 cout << '\n'; 
 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Nova sintaxe para funções 
 
O novo padrão da linguagem C++ nos permite definir funções de uma nova 
forma: auto funcao()-> double, auto funcao()-> int. 
A primeira coisa a se colocar é a palavra auto, em seguida o nome da função, 
abrir parênteses e colocar ou não parâmetros para a função, fechar 
parênteses, colocar o operador -> e por ultimo dizer qual será o tipo de retorno 
da função. 
 
Sua principal utilização é para templates que será mostrada posteriormente. 
 
 
#include <iostream> 
 
using namespace std; 
 
//Retorna o menor entre 2 doubles 
auto menorEntreDoisDoubles(double a, double b) -> double 
{ 
 return a < b ? a : b; 
} 
//Retorna o menor entre 2 ints 
auto menorEntreDoisInts(int a, int b) -> int 
{ 
 return a < b ? a : b; 
} 
//Imprime Funcao!!! 
auto funcao() -> void 
{ 
 cout << "\nFuncao!!!\n"; 
} 
 
int main() 
{ 
 cout << menorEntreDoisDoubles(1.2, 2.2) << '\n'; 
 cout << menorEntreDoisInts(1, 2) << '\n'; 
 funcao(); 
 return 0; 
} 
 
 
Lambdas 
 
Lambdas são um dos recursos mais aguardados do C++, lambdas são funções 
sem nome que você pode escrever inline em seu código fonte e podem ser 
utilizadas em locais onde funções tradicionais seriam usadas. 
A sintaxe para a criação das lambdas é a seguinte: 
 
[captura](parametros)mutable exception attribute -> retorno {corpo} 
[captura](parametros) -> retorno {corpo} 
[captura](parametros) {corpo} 
[captura]{corpo} 
 
 
Uma lambda embora não possua um nome pode ser chamada através de uma 
variável auto. 
 
#include <iostream> 
 
using namespace std; 
 
double menor(double a, double b) 
{ 
 return a < b ? a : b; 
} 
 
// lambdaMenor armazena a lambda 
auto lambdaMenor = [](double a, double b) -> double {return a < b ? a : b;}; 
 
int main() 
{ 
 cout << menor(10, 20) << "\n\n"; 
 cout << lambdaMenor(10, 20) << '\n'; 
 return 0; 
} 
 
 
 
 
 
 
 
Exemplo 2: 
 
 
#include <iostream> 
#include <string> 
#include <vector> 
#include <algorithm> 
 
using namespace std; 
 
 
//Classe teste com o operator () escrito (Functor) 
class Teste 
{ 
public: 
 void operator ()(int n) 
 { 
 cout << n << '\n'; 
 } 
}; 
 
void imprime(int n) 
{ 
 cout << n << '\n'; 
} 
 
int main() 
{ 
 vector<int> v1; 
 
 for(int n = 0; n <= 10; ++n) 
 v1.push_back(n); 
 
 
 //Chamando função 
 for_each(v1.begin(), v1.end(), &imprime); 
 //Chamando functor 
 for_each(v1.begin(), v1.end(), Teste()); 
 //Lambda 
 for_each(v1.begin(), v1.end(), [](int n) {cout << n << '\n';} ); 
 
 
 return 0; 
} 
Exemplo 3 
 
#include <iostream> 
#include <string> 
#include <vector> 
#include <algorithm> 
 
using namespace std; 
 
//Objeto função(functor) 
class Teste 
{ 
public: 
 void operator ()(int n) 
 { 
 cout << n << '\n'; 
 } 
}; 
 
//Função imprime 
void imprime(int n) 
{ 
 cout << n << '\n'; 
} 
 
int main() 
{ 
 vector<int> v1; 
 //Adicionando elementos ao vetor 
 for(int n = 0; n <= 10; ++n) 
 v1.push_back(n); 
 
 for_each(v1.begin(), v1.end(), &imprime); 
 for_each(v1.begin(), v1.end(), Teste()); 
 
 int j = 3; 
 static int k = 4; 
 //[] acessa variaveis externas no lambda 
 //Caso queria colocar mais de 1 variavel j,v,l,p 
 //Caso queira pegar todas = (pega por valor) 
 //for_each(v1.begin(), v1.end(), [=](int n) {cout << n * j * k << '\n';} ); 
 //Caso queira pegar todas & (pega por referencia) 
 //for_each(v1.begin(), v1.end(), [&](int n) {cout << n * j * k << '\n';} ); 
 //Quando a variavel eh static ou global nao precisa capturar pois são 
capturadas por default 
 for_each(v1.begin(), v1.end(), [&j](int n) {cout << n * j * k << '\n';} ); 
 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Callable objects 
 
Um callable object é qualquer coisa que pode ser chamado como uma função. 
Funções 
Lambdas 
Functors (objetos função) 
 
 
Para armazenar um objeto função a biblioteca padrão C++ nos fornece o objeto 
std::function que esta declarado dentro do arquivo header <functional>. 
 
#include <iostream> 
#include <functional> 
 
 
using namespace std; 
 
 
class Matematica 
{ 
public: 
 int operator ()(int a, int b) 
 { 
 return a + b; 
 } 
}; 
 
int soma(int a, int b) 
{ 
 return a + b; 
} 
 
void imprimeHello() 
{ 
 cout << "Hello!!!" << '\n'; 
} 
 
 
 
 
 
int main() 
{ 
 //Armazenando função 
 function<int(int, int)> f1 = soma; 
 //Armazenando functor 
 function<int(int, int)> f2 = Matematica(); 
 //Armazenando lambda 
 function<int(int, int)> f3 = [](int a, int b){return a + b;}; 
 
 cout << "Funcao: " << f1(10, 90) << '\n'; 
 cout << "Functor: " << f2(10, 90) << '\n'; 
 cout << "Lambda: " << f3(10, 90) << '\n'; 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Type alias 
 
No novo padrão do C++ podemos usar a declaração using para criar sinônimos 
para tipos no lugar de typedef. 
 
#include <iostream> 
#include <vector> 
 
using namespace std; 
 
//Cria sinonimos para vector<int> e vector<double> 
using vecInt = vector<int>; 
using vecDouble = vector<double>; 
 
typedef vector<int> vec; 
 
int main() 
{ 
 vecInt i; 
 i.push_back(1); 
 cout << i[0] << '\n'; 
 
 vecDouble d; 
 d.push_back(1.1); 
 cout << d[0] << '\n'; 
 return 0; 
} 
 
 
 
#include <iostream> 
#include <vector> 
 
using namespace std; 
 
 
template <class vec> using vetor = std::vector<vec>;int main() 
{ 
 
 vector<char> str; 
 
 str.push_back('A'); 
 str.push_back('G'); 
 str.push_back('I'); 
 str.push_back('T'); 
 
 for(auto it: str) 
 cout << it; 
 
 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Inicialização uniforme 
 
 
No padrão anterior de C++ (C++ 98) haviam varias maneiras de se inicializar 
uma variável, entretanto no novo padrão C++ 11 foi introduzido uma nova 
forma de inicialização a inicialização uniforme 
 
#include <iostream> 
 
using namespace std; 
 
int main() 
{ 
 int vetor[]{1, 2, 3, 4, 5}; 
 int vetor_2[] = {1, 2, 3, 4, 5};//Podemos usar = na inicialização 
 
 int a{0}; 
 int b = {0}; 
 
 
 cout << "Inicializacao: int vetor[]{1, 2, 3, 4, 5};\n"; 
 for(int i = 0; i < 5; ++i) 
 cout << vetor[i] << '\n'; 
 
 
 cout << "\n\nInicializacao: int vetor_2[] = {1, 2, 3, 4, 5};\n"; 
 for(int i = 0; i < 5; ++i) 
 cout << vetor_2[i] << '\n'; 
 
 cout << "\n\nInicializacao: int a{0};\n" << a; 
 cout << "\n\nInicializacao: int b = {0};\n" << b; 
 
 
 cout << "\n\n"; 
 return 0; 
} 
 
 
Listas inicializáveis 
 
No novo padrão C++ 11 foi introduzido o template std::initializer_list<> para 
armazenar uma coleção de valores que devem ser do mesmo tipo, assim como 
os arrays. 
Para armazenarmos valores nessa lista usamos as chaves {}. 
Para percorrermos um initializer_list usamos iterator assim como qualquer 
outra classe container. 
As construtoras de classes que recebem um initializer_list como parametro tem 
precedência sobre as outras. 
 
#include <iostream> 
#include <initializer_list> 
 
using namespace std; 
 
class Inicializa 
{ 
public: 
 //Construtora que recebe dois ints e exibe a soma 
 Inicializa(int a, int b){cout << "\n***Inicializa(int a, int b)***\n" << a + b << '\n';} 
 //Construtora que recebe uma lista de inicialização e imprime os itens 
recebidos na tela 
 Inicializa(initializer_list<int> l) 
 { 
 cout << "\n***Inicializa(initializer_list<int> l)***\n"; 
 //Percorre os elementos da lista e exibe na tela 
 for(auto it = l.begin(); it < l.end(); it++) 
 cout << *it << '\n'; 
 } 
}; 
 
int main() 
{ 
 Inicializa s1{1, 2};//Chama Inicializa(initializer_list<int> l) 
 Inicializa s2(10, 20);//Chama Inicializa(int a, int b) 
 
 return 0; 
} 
 
 
A classe vector também possui uma construtora initializer_list. 
 
#include <iostream> 
#include <initializer_list> 
#include <vector> 
 
using namespace std; 
 
int main() 
{ 
 //Nessa primeira declaração estamos dizendo a classe vector que queremos 
 //50 elementos de numeros inteiros contendo o valor 10 em cada um deles 
 vector<int> v1(5, 10); 
 
 //a classe vector tambem possui um initializer list e nesse caso estamos 
dizendo 
 //a classe vector que queremos 2 elementos inteiros, um com o valor 5 e 
outro com valor 10 
 vector<int> v2{5, 10}; 
 
 
 for(auto it = v1.begin(); it < v1.end(); it++) 
 cout << *it << '\n'; 
 
 cout << "\n"; 
 
 for(auto it = v2.begin(); it < v2.end(); it++) 
 cout << *it << '\n'; 
 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
 
 
 
 
Referencias rvalues 
 
Antes de começarmos a falar sobre rvalue e lvalue primeiro devemos entender 
o que eles são. Um lvalue é tudo aquilo que pode receber uma atribuição 
como, por exemplo: int a = 5; 
“a” é o valor que esta a esquerda da operação e “a” por ser uma variável pode 
receber uma atribuição portanto “a” sempre será um lvalue independente da 
posição em que esteja, seja do lado direito ou esquerdo, já o valor 5 é um 
rvalue, pois 5 é uma memória temporária que esta a direita da operação. 
 
A referencia rvalue pode referenciar uma memória temporária, ao contrario da 
referencia tradicional que só pode referenciar um lvalue. 
As regras para as referencias rvalues continuam sendo as mesmas que para 
as lvalues, ou seja, não podem referenciar outra região de memória e devem 
sempre ser inicializadas. 
A referência rvalue tem dois objetivos principais: 
 
A semântica move que permite mover o estado de objetos; 
 
Encaminhamento perfeito (perfect forwarding): que permite que um template de 
função repasse os parâmetros recebidos da mesma forma, lvalue para lvalue e 
rvalue para rvalue. 
 
#include <iostream> 
 
using namespace std; 
 
//Passagem de parametros por referencia lvalue 
int soma(int &a, int &b) 
{ 
 return a + b; 
} 
//Passagem de parametros por referencia Rvalue 
int somaComRvalue(int &&a, int &&b) 
{ 
 return a + b; 
} 
 
 
 
 
int main() 
{ 
 int a; 
 int &b = a;//Referencia lvalue 
 //int &c = 10;//Erro, nao pode referenciar um rvalue 
 int &&d = 10;//No novo padrão podemos referenciar um rvalue 
 int x = 10, y = 20; 
 
 
 //cout << soma(10, 20) << '\n';//Erro pois somos obrigados a passar um 
lvalue 
 cout << "Soma Lvalue: " << soma(x, y) << '\n';//Correto 
 cout << "Soma Rvalue: " << somaComRvalue(10, 20) << '\n';//Agora 
podemos passar valores temporarios 
 
 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Semântica move 
 
Através da semântica move, o estado de um objeto pode ser movido a outro, 
ao invés de ser copiado. Isso pode trazer grandes ganhos de performance 
quando os objetos consomem grandes quantidades de memória alocadas 
dinamicamente.. 
 
Como exemplo, podemos usar um vetor alocado no heap. 
Copiar este vetor, significa alocar uma nova memória do mesmo tamanho e 
copiar elemento por elemento. 
 
Mover, significa que podemos pegar o ponteiro do objeto armazenado pela 
origem e mover para o destino, não sendo necessário a alocação de uma nova 
memória e também a cópia individual de cada elemento. 
 
#include <iostream> 
#include <utility> 
#include <vector> 
#include <string> 
 
int main() 
{ 
 std::string str = "Ola mundo"; 
 std::vector<std::string> v; 
 
 //Aqui estamos usando 
 //v.push_back(str); std::vector<std::string>::push_back(value_type &v) 
 //Que terá o custo de copia da string str para dentro do vetor 
 std::cout << "Depois da copia, str eh: " << str << "\n"; 
 
 //Aqui estamos usando a semantica move, o que significa que nenhuma 
string será copiada. 
 //o conteudo da string sera movido para dentro do vetor, ou seja, o vetor 
std::vector<std::string> v; 
 //agora ira conter "Ola mundo" e str ficara vazia 
 v.push_back(std::move(str)); 
 std::cout << "Depois do move, str eh: " << str << "\n"; 
 
 return 0; 
} 
 
#include <iostream> 
 
using namespace std; 
 
//Classe vetor 
class Vetor 
{ 
 //P será um vetor de elementos inteiros que terá seu tamanho definido assim 
que instanciar um objeto da classe vetor 
 int *p; 
 size_t lenght; 
public: 
 //Construtora 
 Vetor(size_t len) 
 { 
 p = new int[len]; 
 lenght = len; 
 } 
 
 //Construtora de cópia por referencia 
 Vetor(Vetor &v) 
 { 
 //Aloca p 
 p = new int[v.lenght]; 
 //Copia elemento por elemento 
 for(int n = 0; n < v.lenght; ++n)p[n] = v.p[n]; 
 
 lenght = v.lenght; 
 cout << "Copia\n"; 
 } 
 
 //Construtora move, move os dados de os dados temporarios de uma classe 
para outra. 
 Vetor(Vetor &&v) 
 { 
 cout << "Move\n"; 
 //Ao inves de copiar elemento por elemento fazemos com que p da nova 
instancia aponte para p da outra instancia 
 p = v.p; 
 lenght = v.lenght; 
 v.p = nullptr; 
 v.lenght = 0; 
 } 
 //Sobrecarga do operador [] para podermos acessar os index 
 int &operator [] (int index) 
 { 
 return p[index]; 
 } 
 //Destrutora 
 ~Vetor() 
 { 
 delete []p; 
 p = nullptr; 
 } 
}; 
//Cria um vetor temporario de 5 elementos 
Vetor func() 
{ 
 Vetor v(5); 
 v[0] = 1; 
 return v; 
} 
//Cria um vetor de 5 elementos 
Vetor *func_2() 
{ 
 Vetor *v = new Vetor(5); 
 (*v)[0] = 10; 
 return v; 
} 
 
int main() 
{ 
 //Chama a construtora move 
 Vetor v2(move(func())); 
 //Chama a construtora de cópia 
 Vetor v3(*func_2()); 
 return 0; 
} 
 
 
 
 
 
 
 
 
Perfect forward 
 
 
Utilizado em templates de função para manter o estado lvalue ou rvalue 
quando repassar os argumentos a outras funções. 
É implementado através de std::forward. 
 
 
#include <iostream> 
 
 
using namespace std; 
 
//Class a com construtor que recebe um rvalue e um lvalue 
struct A 
{ 
 A(int&& n) 
 { 
 std::cout << "rvalue overload, n=" << n << "\n"; 
 } 
 A(int& n) 
 { 
 std::cout << "lvalue overload, n=" << n << "\n"; 
 } 
}; 
 
//Instancia um objeto da classe especificada no template que recebe um 
parametro especificado 
//&& && = && 
//&& & = & 
//& && = & 
//& & = & 
 
template<class T, class U> 
T* instancia_objeto(U&& u) 
{ 
 //forward nos garante que o parametro sera passado exatamente como veio, 
ou seja, rvalue sera passado como rvalue 
 //e lvalue sera passado como l value 
 return (new T(forward<U>(u))); 
} 
 
int main() 
{ 
 A* p1 = instancia_objeto<A, int&&>(2); // rvalue 
 int i = 1; 
 A* p2 = instancia_objeto<A, int&>(i); // lvalue 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Funções membro default 
 
Por padrão, algumas funções especiais são acrescentadas às classes quando 
necessário, estas funções são: 
 
- Construtora padrão; 
- Construtora de cópia; 
- Construtora move; 
- Operador de atribuição para cópia; 
- Operador de atribuição para mover; 
- Destrutora. 
 
Estas funções são declaras: public/inline e não explicitas. 
Podemos especificar em nossas classes que estas funções devem usar a 
implementação padrão explicitamente: 
 
Exemplo: 
#include <iostream> 
 
using namespace std; 
 
 
class Teste 
{ 
public: 
 Teste(int i) 
 { 
 } 
 Teste() = default; 
}; 
 
int main() 
{ 
 Teste a; 
 return 0; 
} 
 
 
Na classe acima, se não tivéssemos declarado a construtora padrão como 
default, ela não existiria e somente a construtora que recebe um int poderia ser 
usada. 
Funções delete 
 
Podemos deletar qualquer função através da declaração delete, ao invés de 
colocar as mesmas como membros privates usamos o delete. 
O uso mais comum para delete é não permitir a cópia ou mover um objeto. 
 
#include <iostream> 
 
using namespace std; 
 
 
class teste 
{ 
public: 
 teste( const teste &t ) = delete; 
 teste & operator = ( const teste & ) = delete; 
 teste() = default; 
}; 
 
int main() 
{ 
 teste a; 
 return 0; 
} 
 
Note que se você deletar as operações de cópia, estará automaticamente 
deletando as operações de mover e vice-versa. 
 
Como dito, qualquer função pode ser deletada: 
 
void func( void *p ) {} 
void func( const char *) = delete; 
 
Funções virtuais podem ser deletadas, e neste caso todas as funções desde a 
classe base serão deletadas. 
 
 
 
 
 
 
Inicialização de membros in-class 
 
Podemos inicializar qualquer membro in-class sem que haja a necessidade de 
inicializar na lista de inicialização ou na construtora da classe. 
 
 
#include <iostream> 
 
using namespace std; 
 
 
class teste 
{ 
 int a = 5; 
 int b { 3 }; 
 //int c(0); // erro – não pode usar inicialização direta 
 int d = a*b; // ok 
 //static int e = 3; // erro, deve ser inicializada fora 
 const int f = 6; 
public: 
 teste(int var) : a(var) {} // prevalece a lista de inicialização 
 teste() = default; 
}; 
 
 
int main() 
{ 
 teste h; 
 return 0; 
} 
 
As inicialização in-class elimina o código redundante de inicialização das 
construtoras. 
Útil quando os membros devem ter o mesmo valor de inicialização 
independente da construtora. 
Inicializar um membro in-class faz com que o tipo se torne não agregado. 
 
 
 
 
 
Delegando construtoras 
 
Uma construtora pode delegar a inicialização de outra construtora, ou seja, ao 
uma construtura ser chamada pode disparar outra, só não pode delegar ela 
mesma, não pode conter mais nada na lista de inicialização, uma construtora 
pode delegar outra que delega outra e assim por diante, o corpo da construtora 
que delegou será executado assim que a construtora delegada terminar. 
 
#include <iostream> 
 
 
using namespace std; 
 
 
class Teste 
{ 
 int a, b; 
public: 
 //Delegando (chamando outra construtora 
 //OBS: Nao pode conter nenhuma outra inicicializacao a nao ser de 
construtoras 
 Teste() : Teste(0) 
 { 
 cout << "Sem paramentro\n\n"; 
 } 
 Teste(int a) : Teste(0, 0) 
 { 
 cout << "Com 1 paramentros\n\n"; 
 } 
 Teste(int Pa, int Pb) : a(Pa), b(Pb) 
 { 
 cout << "Com 2 paramentros\n\n"; 
 } 
}; 
 
int main() 
{ 
 Teste t; 
 
 return 0; 
} 
Final e override 
 
As palavras final e override são palavras reservadas dependendo do contexto 
onde aparecem. 
 
final: pode ser usada para uma classe ou para uma função virtual. Se usado 
para uma classe, indica que esta não pode ser herdada. Já para uma função 
virtual indica que ela não pode ser redefinida na classe derivada. 
override: Usado para informar que a função está sobrecarregando uma virtual 
da classe base. 
 
Final 
 
#include <iostream> 
using namespace std; 
class Base final 
{ 
public: 
 int a; 
}; 
/*Gera erro de compilação, pois base não pode ser herdada 
class Derivada : public Base 
{ 
public: 
 int b; 
};*/ 
class VirtualFinal 
{ 
public: 
 virtual void f() final{} 
}; 
/*Gera erro de compilação, pois f() não pode ser redefinida 
class DerivadaVirtualFinal: public VirtualFinal 
{ 
public: 
 void f(){} 
};*/ 
int main() 
{ 
 return 0; 
} 
Override 
 
#include <iostream> 
 
using namespace std; 
 
 
struct Base 
{ 
 virtual void f() 
 { 
 cout << "F Base.\n"; 
 } 
public: 
 void executaF() 
 { 
 f(); 
 } 
}; 
 
struct Derivada : Base 
{ 
 //Indica que estamos reescrevendo a virtual da base 
 virtual void f() override{ 
 cout << "Derivada override.\n"; 
 } 
}; 
 
int main() 
{ 
 Derivada de; 
 
 de.executaF(); 
 return 0; 
} 
 
 
 
Static assert 
 
Executa uma verificação em tempo de compilação para ver se a condição 
especificada é verdadeira, ou falsa. 
A sintaxe para static_assert é a seguinte: 
 
static_assert(condição, mensagem de erro); 
 
Caso a condição retorne false, teremos erro de compilação e a mensagem de 
erro especificada no segundo parâmetro será escrita. 
 
 
#include <iostream> 
 
using namespace std; 
 
template<typename Tipo, unsigned int Tamanho> 
class Vetor 
{ 
 Tipo m_Element[Tamanho]; 
public: 
 Vetor() 
 { 
 //Se o vetor for menor ou igual a 10, a condição é true e esta correto. 
 //Caso contrário é false e teremos erro de compilação 
 static_assert(Tamanho <= 10, "Não pode criar um vetor com mais de 10 
elementos."); 
 } 
}; 
 
 
int main() 
{ 
 Vetor<int, 10> vec;//Correto, Tamanho <= 10 = true 
 Vetor<int, 11> vec_2;//Incorreto, Tamanho <= 10 = false; 
 
 return 0; 
} 
 
Operadores de conversão explicit 
 
Em C++ quando criamos uma classe, podemos criar nossos próprios 
operadores de cast. 
O problema é que esses cast podem ser executados de forma implícita, 
dificultando a leitura do código, para corrigir isso C++ 11 introduziu os 
operadores de conversão explicit, onde podemos forçar uma conversão 
explicita. 
 
#include <iostream> 
 
 
using namespace std; 
 
 
class converteImplicito 
{ 
public: 
 int m_var = 0; 
 //Operadores de conversão implicitos 
 operator int() 
 { 
 return m_var; 
 } 
}; 
 
 
class converteExplicito 
{ 
public: 
 int m_var = 0; 
 //Operadores de conversão explicitos 
 explicit operator int() 
 { 
 return m_var; 
 } 
}; 
 
 
 
 
int main() 
{ 
 converteImplicito convImpl, convImpl_2; 
 
 int a = 10; 
 cout << "a antes: " << a << '\n'; 
 //Isso nos deixa confuso. 
 //convImpl é um int ou é uma classe??? 
 a = convImpl; 
 cout << "a depois: " << a << '\n'; 
 
 //Como assim?? o que estamos comparando?? 
 if(convImpl == convImpl_2) 
 cout << "convImpl e convImpl_2 sao iguais\n\n"; 
 
 
 
 converteExplicito convExpl, convExpl_2; 
 
 int b = 10; 
 cout << "b antes: " << b << '\n'; 
 
 //Somos obrigados a forçar o cast explicitamente, deixando claro que 
estamos convertendo pra int 
 b = int(convExpl); 
 cout << "b depois: " << b << '\n'; 
 
 //Somos obrigados a forçar o cast explicitamente, deixando claro que 
estamos convertendo pra int 
 if(int(convExpl) == int(convExpl_2)) 
 cout << "convExpl e convExpl_2 sao iguais\n\n"; 
 
 return 0; 
} 
 
 
 
 
 
Decltype 
 
Retorna o tipo de uma expressão sem avaliá-la. 
O uso mais comum para decltype é para especificar o tipo de retorno de um 
template quando este depende dos tipos do parâmetros. 
 
#include <iostream> 
 
using namespace std; 
 
//Dependemos que o programador passe corretamente os tipos, tendo em 
mente que ele sempre 
//Passara o tipo maior primeiro, mas isso pode não acontecer 
template<typename MAIOR, typename MENOR> 
MAIOR RetornaMaior(MAIOR mai, MENOR men) 
{ 
 return mai > men ? mai : men; 
} 
 
//decltype(mai + men) ira retornar o tipo do maior 
template<typename MAIOR, typename MENOR> 
auto RetornaMaiorDecltype(MAIOR mai, MENOR men) -> decltype(mai + men) 
{ 
 return mai > men ? mai : men; 
} 
 
int main() 
{ 
 //Funciona perfeitamente 
 cout << "Sucesso RetornaMaior<double, int>(19.99, 10): " << 
RetornaMaior<double, int>(19.99, 10) << '\n'; 
 
 //Funciona erroneamente, pois truca o valor 
 cout << "Falha RetornaMaior<int, double>(10, 19.99): " << RetornaMaior<int, 
double>(10, 19.99) << '\n'; 
 
 //Funciona perfeitamente 
 cout << "Sucesso RetornaMaiorDecltype<int, double>(10, 19.99): " << 
RetornaMaiorDecltype<int, double>(10, 19.99) << '\n'; 
 return 0; 
} 
Templates variadics 
 
Os templates agora podem ter uma quantidade variável de argumentos. 
template<typename ...Args> class Sample; 
template<typename T, typename ...Args> T funcao(Args …args); 
Em uma lista de parâmetros de função, o parâmetro a ser expandido deve 
aparecer por último. 
Geralmente, a manipulação de um template variadic é feita através de 
recursividade, onde se analisa o primeiro parâmetro e passa o resto dos 
argumentos para o template novamente. 
As únicas operações que podem ser feitas sobre a lista de parâmetros 
variáveis são (…) para se referir à lista e sizeof...() para descobrir a quantidade 
de elementos na lista. 
 
Exemplo 1: 
 
#include <stdexcept> 
#include <iostream> 
 
using namespace std; 
 
//Conta numero de parametros do template 
template <class ...A> 
int func(A... arg) 
{ 
 return sizeof...(arg); 
} 
 
int main(void) 
{ 
 cout << func(1,2,3,4,5,6) << '\n'; 
 return 0; 
} 
 
 
 
 
 
 
 
 
Exemplo 2: 
 
Essa declaração pode parecer estranha. Isso porque argumentos de modelo 
variadics são percorridos de forma recursiva, em vez de forma iterativa. 
Abordamos o primeiro argumento da função, e depois uma chamada a função 
usando o resto dos argumentos. 
Observe como nós definimos duas sobrecargas de função aqui. Uma das 
sobrecargas de função não tem argumentos porque C + + precisa saber como 
terminar a recursão. Se essa sobrecarga não for especificada, então C++ vai 
dar um erro quando não encontrar uma versão da soma que não leva 
argumentos. 
 
#include <iostream> 
 
using namespace std; 
 
 
//Repare que para capturarmos o parametro real da função fomos obrigados a 
criar 
//uma sobrecarga da função func e se retirarmos void func(){} o programa não 
compila 
void func(){} 
 
template <typename Valor, class ...Parametros> 
void func(Valor cabeca, Parametros... calda) 
{ 
 cout << "A: " << cabeca << endl; 
 //Chama a propia função passando parametro por parametro capturado 
 //Quando chegar ao ultimo parametro C++ precisa encontrar uma função 
com mesmo nome 
 //Que não leve parametros para saber onde tudo termina, caso contrario 
teremos erro de compilação 
 func(calda...); 
} 
 
int main(void) 
{ 
 func(1,2,3,4,5,6); 
 
 return 0; 
} 
 
 
 
Controle de Alinhamento 
 
 
Muitas instruções executadas pelos processadores atuais, requerem que os 
dados sejam alinhados na memória e além disso, alinhar dados 
frequentemente utilizados no cache pode aumentar a performance. 
Antes do C++11, eram os compiladores que forneciam maneiras específicas 
para modificar ou consultar informações sobre o alinhamento. Agora podemos 
fazer isso de forma padronizada usando alignof() e alignas(). 
 
 
#include <iostream> 
 
using namespace std; 
 
 
struct Alinhamento 
{ 
 double a; 
 int b; 
 short c; 
 bool d; 
 char e; 
}; 
 
int main() 
{ 
 //Alinhamento default, alinhou pelo maior tipo ,ou seja, double 8 bytes 
 cout << sizeof(Alinhamento) << '\n'; 
 //Pergunta o alinhamento em bytes 
 cout << alignof(Alinhamento) << '\n'; 
 
 //Mudamos o alinhamento de memoria. 
 alignas(4) Alinhamento a; 
 
 cout << sizeof(a) << '\n'; 
 cout << alignof(a) << '\n'; 
 
 return0; 
} 
 
Literais definidos pelo usuário 
 
 
C + +11 introduziu a capacidade de adicionar sufixos personalizados para 
literais, a fim de fornecer valores diferentes. Sufixos literais podem ser 
sobrecarregados de uma forma muito semelhante aos operadores. 
Através dos literais definidos pelo usuário, qualquer tipo de dados pode ter sua 
representação literal. 
 
 
#include <iostream> 
 
using namespace std; 
 
long double operator"" _POW(long double BASE) 
{ 
 return BASE * BASE; 
} 
 
int main() 
{ 
 double x = 2.0_POW; 
 cout << x << '\n'; 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Namespace inline 
 
Namespaces servem para evitar a coalizão de nomes em projetos grandes. 
Os nomes declarados dentro de um namespace ficam dentro de um escopo, o 
que previne de haver coalizões com outros nomes iguais e outras partes do 
projeto. 
Em C++ 11 foram inseridos os namespaces inline que servem para tornar o 
uso de um namespace opcional. 
 
#include <iostream> 
 
using namespace std; 
 
namespace Sample 
{ 
 //Torna o uso de inner opicional 
 inline namespace Inner 
 { 
 int a; 
 } 
} 
 
int main() 
{ 
 //Da no mesmo 
 Sample::Inner::a = 1; 
 Sample::a = 1; 
 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
 
 
Smart pointers 
 
O principal uso de smart pointers no C++ é simplificar o gerenciamento de 
memórias alocadas dinamicamente, principalmente nos momentos em que 
ocorrem exceções. 
Para isso, foram adicionados os seguintes smart pointers: 
 
- std::shared_ptr<> 
- std::weak_ptr<> 
- std::unique_ptr<> 
 
Além do já existente std::auto_ptr<> que pelas suas limitações é considerado 
obsoleto. 
Todos esses smart pointers são declarados no arquivo <memory>. 
 
Shared ptr 
 
Permitem compartilhar uma memória alocada por N ponteiros e guarda um 
contador de referencias que é incrementado em 1 a cada novo ponteiro que 
compartilhar a mesma memória. 
Quando o contador chegar a 0 a memória será desalocada automaticamente. 
 
#include <iostream> 
#include <memory> 
 
using namespace std; 
 
int main() 
{ 
 shared_ptr<int> pI(new int(0)); 
 
 cout << "Contador: " << pI.use_count() << "\n\n"; 
 { 
 shared_ptr<int> pI_2(pI); 
 cout << "Contador: " << pI_2.use_count() << "\n\n"; 
 } 
 
 cout << "Contador: " << pI.use_count() << "\n\n"; 
 
 return 0; 
} 
Weak Ptr 
 
std::weak_ptr<>: Usado em conjunto com um std::shared_ptr<> pode dizer se o 
ponteiro continua ou não válido. Quando o contador de um std::shared_ptr<> 
chegar a zero, todos os std::weak_ptr<> relacionados a eles expiram. 
 
#include <iostream> 
#include <memory> 
 
using namespace std; 
 
int main() 
{ 
 shared_ptr<int> pI_shared(new int(0)); 
 cout << "Contador: " << pI_shared.use_count() << '\n'; 
 
 //Não aumenta o contador 
 weak_ptr<int> pI_weak(pI_shared); 
 cout << "Contador: " << pI_shared.use_count() << '\n'; 
 
 //Verifica se o ponteiro não esta expirado 
 if(!pI_weak.expired()) 
 cout << "Nao expirado!!!\n"; 
 else 
 cout << "Expirado!!!\n"; 
 
 cout << "Contador: " << pI_shared.use_count() << '\n'; 
 //Expira o ponteiro 
 pI_shared.reset(); 
 
 //Verifica se o ponteiro não esta expirado 
 if(!pI_weak.expired()) 
 cout << "Nao expirado!!!\n"; 
 else 
 cout << "Expirado!!!\n"; 
 
 return 0; 
} 
 
 
 
 
 
 
Um std::weak_ptr<> não pode na verdade ser usado com um smart pointer, 
pois, não possui os operadores de * e → que permitem o acesso ao ponteiro. 
Para usar um std::weak_ptr<>, temos que criar um std::shared_ptr<> a partir 
dele. 
OBS: Se o std::weak_ptr estiver inválido, então o std::shared_ptr irá conter um 
ponteiro nulo. 
 
 
#include <iostream> 
#include <memory> 
 
using namespace std; 
 
int main () 
{ 
 //Apenas cria shared_ptr, sem instanciar nada no heap 
 shared_ptr<int> sp1,sp2; 
 //Apenas cria shared_ptr, sem apontar pra nenhum shared_ptr 
 weak_ptr<int> wp; 
 
 //Instancia um int no heap e faz sp1 apontar para esse int 
 sp1 = std::make_shared<int> (20); 
 wp = sp1; //agora weak_ptr wp aponta para sp1 
 sp2 = wp.lock(); //Retorna o shared_ptr 
 
 sp1.reset(); //Resseta o ponteiro 
 
 sp1 = wp.lock(); //Poe novamente o int alocado no heap 
 
 std::cout << "*sp1: " << *sp1 << '\n'; 
 std::cout << "*sp2: " << *sp2 << '\n'; 
 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
 
Unique Ptr 
 
std::unique_ptr<> é o sucessor de std::auto_ptr<>, mas possui várias 
melhorias, como por exemplo pode armazenar ponteiros para arrays. 
Obs: Um std::unique_ptr<> não pode ser copiado, mas somente movido. 
 
 
#include <iostream> 
#include <memory> 
 
using namespace std; 
 
int main() 
{ 
 //Cria um unique_ptr que instancia um int no heap 
 unique_ptr<int> u(new int(123)); 
 cout << *u << '\n'; 
 
 //Move o conteudo do ponteiro de u para u2 
 unique_ptr<int> u2(move(u)); 
 //cout << *u << '\n';//Erro, porque o conteudo de um foi movido para u2, ou 
seja, u agora é nulo 
 //unique_ptr<int> u3(i); Erro pois nao permite copia 
 
 //Aloca um vetor de 10 inteiros no heap 
 unique_ptr<int []> uv(new int[10]); 
 
 //Insere dados no vetor 
 for(int i = 0; i < 10; ++i) 
 uv[i] = i; 
 
 //Exibe os dados 
 for(int i = 0; i < 10; ++i) 
 cout << uv[i] << '\n'; 
 
 return 0; 
} 
 
 
 
 
 
 
Novas classes containers 
 
std::forward_list<>: lista ligada unidirecional, declarado no arquivo 
<forward_list>; 
tabelas hash: Tipos de containers associativos que usam uma chave para 
localizar um elemento. Quatro templates podem ser usados: unordered_map<> 
e unordered_multimap<> declarados em <unordered_map> e unordered_set<> 
e unordered_multiset<> declarados em <unordered_set>. 
tuple<>: Container de tamanho fixo que armazena valores de tipos diferentes. 
Declarado em <tuple>. Para acessar um valor individual usa-se o template de 
função get<>() passando como argumento o índice do elemento desejado. 
std::array: Declarado em <array>, criado para armazenar um array de tamanho 
fixo com performance semelhante ao arrays da linguagem C. 
 
Forward list 
 
Lista ligada unidirecional, só é possível inserir elementos a partir do inicio. 
 
Exemplo 1 
 
#include <iostream> 
#include <forward_list> 
#include <iterator> 
 
using namespace std; 
 
//Exibe conteudo da forward_list 
template<typename Tipo> 
void imprimeForward_List(forward_list<Tipo> li) 
{ 
 cout << "\n\n"; 
 for(auto it: li) 
 cout << it << '\n'; 
} 
 
int main() 
{ 
 //Monta forward_list com 5 elementos 
 forward_list<int> list = {3, 4, 5, 6, 7}; 
 //Exibe 
 imprimeForward_List(list); 
 
 //Insere antes do primeiro elemento 
 list.insert_after(list.before_begin(), 1); 
 imprimeForward_List(list); 
 
 //Insere depois do primeiro elemento 
 list.insert_after(list.begin(), 2); 
 imprimeForward_List(list); 
 
 //Insere antes do primeiro elemento 
 list.push_front(0); 
 imprimeForward_List(list); 
 
 //list.insert_after(list.end(), 8); //Erro,não pode inserir elementos no fim 
 
 return 0; 
} 
 
 
Exemplo 2 
 
#include <forward_list> 
#include <iostream> 
#include <algorithm> 
#include <iterator> 
#include <string> 
 
using namespace std; 
 
//Imprime conteudo das listas 
void printLists(const string title, const forward_list<int>& l1, const 
forward_list<int>& l2) 
{ 
 cout << title << endl; 
 cout << " list1: "; 
 for(auto it: l1) 
 cout << it << " "; 
 
 cout << endl << " list2: "; 
 for(auto it: l2) 
 cout << it << " "; 
 cout << endl; 
} 
 
int main() 
{ 
 //Cria duas forward_list 
 forward_list<int> list1 = { 1, 2, 3, 4 }; 
 forward_list<int> list2 = { 66, 77, 88, 99 }; 
 
 //Exibe as listas 
 printLists ("Inicio:", list1, list2); 
 
 //Insere 55 antes do primeiro elemento (66) 
 list2.insert_after(list2.before_begin(), 55); 
 //Insere 44 antes do primeiro elemento (55) 
 list2.push_front(44); 
 //Insere 11, 22, e 33 antes primeiro elemento (44) 
 list2.insert_after(list2.before_begin(), {11,22,33} ); 
 
 printLists ("\n\n5 novos elementos em list2:", list1, list2); 
 
 //Insere todos os elementos da lista2 dentro da lista 1 
 list1.insert_after(list1.before_begin(), list2.begin(), list2.end()); 
 printLists ("\n\nInsere todos os elementos de list2 em list1:", list1, list2); 
 
 //Deleta o segundo elemento da list2, ou seja, 22 
 list2.erase_after(list2.begin()); 
 printLists ("\n\nDeleta o segundo elemento da list2, ou seja, 22:", list1, list2); 
 
 //find irá apagar todos os elementos após 77 
 list2.erase_after(find(list2.begin(),list2.end(), 77), list2.end()); 
 printLists ("\n\nDeleta o elemento 99 da list2:", list1, list2); 
 
 //Reordena as posições 
 list1.sort(); 
 //copia list1 dentro de list2 
 list2 = list1; 
 //Remove duplicações 
 list2.unique(); 
 printLists ("\n\nsorted e unique:", list1, list2); 
 //Retira todos os elementos de list2 e insere em list1 
 list1.merge(list2); 
 printLists ("\n\nmerged:", list1, list2); 
 
 return 0; 
} 
Unordered map 
 
unordered_map são containners associativos que armazenam os elementos 
formados pela combinação de um valor e uma chave, e que permite a rápida 
recuperação de elementos individuais com base em suas chaves. 
 
#include <unordered_map> 
#include <string> 
#include <iostream> 
 
using namespace std; 
 
int main() 
{ 
 unordered_map<string, int> coll{ 
 { "unordered_map_10", 10 }, 
 { "unordered_map_20", 20 } 
 }; 
 
 //Imprime o elemento e a chave 
 for (const auto& elem : coll) 
 cout << elem.first << ": " << elem.second << endl; 
 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Unordered multimap 
 
unordered_map são containners associativos que armazenam os elementos 
formados pela combinação de um valor e uma chave, assim como recipientes 
unordered_map, mas permitindo que os diferentes elementos tenham chaves 
equivalentes 
 
#include <unordered_map> 
#include <string> 
#include <iostream> 
 
using namespace std; 
 
int main() 
{ 
 unordered_multimap<string, int> coll{ 
 {"unordered_map_10", 10}, 
 {"unordered_map_10", 10} 
 }; 
 
 //Imprime o elemento e a chave 
 for (const auto& elem : coll) 
 cout << elem.first << ": " << elem.second << endl; 
 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Unordered set 
 
 
Unordered_set são containers que armazenam elementos únicos em nenhuma 
ordem particular, e que permitem a rápida recuperação de elementos 
individuais com base em seu valor. 
 
#include <unordered_set> 
#include <string> 
#include <iostream> 
 
using namespace std; 
 
int main() 
{ 
 unordered_set<string> coll{"Numero: 111", "Quedinho", "Major", "Rua"}; 
 
 //Imprime o elemento 
 for (auto& it : coll) 
 cout << it << " "; 
 
 cout << "\n\n"; 
 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Unordered multiset 
 
 
Unordered multiset são containners que armazenam elementos sem nenhuma 
ordem particular, permitindo rápida recuperação de elementos individuais com 
base em seu valor, assim como containners unordered_set, mas permitindo 
que os diferentes elementos tenham valores equivalentes. 
 
 
#include <unordered_set> 
#include <string> 
#include <iostream> 
 
using namespace std; 
 
int main() 
{ 
 unordered_multiset<string> coll{"Numero: 111", "Quedinho", "Major", "Rua", 
"Numero: 111", "Quedinho", "Major", "Rua"}; 
 
 //Imprime o elemento 
 for (auto& it : coll) 
 cout << it << " "; 
 
 cout << "\n\n"; 
 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Tuple 
 
Tuples são objetos que armazenam elementos de tipos diferentes ou iguais em 
um único objeto. 
 
#include <tuple> 
#include <iostream> 
#include <complex> 
#include <string> 
using namespace std; 
 
int main() 
{ 
 
 //Cria uma tuple que armazena 5 valores string 
 tuple<string, string, string, string, string> t("Herik", "22 Anos", 
"RG:00.000.000-00", "CPF:000.000.000-00", "11/08/1991"); 
 
 //O Template de função get nos permite acessa cada elemento da tupla 
 cout << get<0>(t) << ", "; 
 cout << get<1>(t) << ", "; 
 cout << get<2>(t) << ", "; 
 cout << get<3>(t) << ", "; 
 cout << get<4>(t) << "\n\n"; 
 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Array 
 
Arrays são containners de tamanho fixo que armazenam um número específico 
de elementos ordenados em sequencia. 
 
#include <array> 
#include <iostream> 
#include <algorithm> 
#include <functional> 
#include <numeric> 
 
using namespace std; 
 
//Imprime todos os elementos 
void imprime(array<int, 10> &a) 
{ 
 for(auto &it : a) 
 std::cout << it << '\n'; 
} 
 
int main() 
{ 
 //Cria um array de ints com 10 elementos 
 array<int,10> a = { 11, 22, 33, 44 }; 
 imprime(a); 
 
 
 cout << "\n\nSoma de todos os elementos: " 
 << accumulate(a.begin(),a.end(),0) 
 << "\n\n"; 
 
 imprime(a); 
 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
Conversão de strings 
 
Em C++ 11 foram inseridas uma serie de funções que convertem uma string 
para tipos numéricos. 
 
O primeiro parâmetro const string &, diz a string que vai ser convertida, 
O segundo parâmetro size_t *idx=0, vai armazenar o numero de dígitos do 
valor a ser convertido e o terceiro int base=0, diz qual base esta sendo 
convertida. 
 
int stoi(const string &, size_t *idx=0, int base=0); 
long stol(const string &, size_t *idx=0, int base=0); 
unsigned long stoul(const string &, size_t *idx=0, int base=0); 
long long stoll(const string &, size_t *idx=0, int base=0); 
unsigned long long stoull(const string &,size_t *idx=0,int base=0); 
float stof(const string &, size_t *idx=0, int base=0); 
double stod(conststring &, size_t *idx=0, int base=0); 
long double stold(const string &, size_t *idx=0, int base=0); 
 
#include <iostream> 
 
using namespace std; 
 
int main() 
{ 
 string str_hexa = "0xF"; 
 string str_decimal = "10"; 
 string str_octal = "012"; 
 string str_bin = "1010"; 
 
 
 size_t *quantidade = new size_t(0); 
 
 //stoi, o primeiro parametro é a string que se quer converter, o segundo 
armazena o numero de digitos, 
 //e o terceiro, diz a base que esta sendo convertida 
 int a = stoi(str_decimal, quantidade , 16); 
 cout << "Conversao(Hexa) de: " << str_hexa << 
 " | para decimal: " << a << " | Quantidade de digitos: " << *quantidade 
<< "\n\n"; 
 
 
 a = stoi(str_decimal, quantidade , 10); 
 cout << "Conversao(Deci) de: " << str_decimal << 
 " | para decimal: " << a << " | Quantidade de digitos: " << *quantidade 
<< "\n\n"; 
 
 a = stoi(str_octal, quantidade , 8); 
 cout << "Conversao(Octal) de: " << str_octal << 
 " | para decimal: " << a << " | Quantidade de digitos: " << *quantidade 
<< "\n\n"; 
 
 
 a = stoi(str_bin, quantidade , 2); 
 cout << "Conversao(Bin) de: " << str_bin << 
 " | para decimal: " << a << " | Quantidade de digitos: " << *quantidade 
<< "\n\n"; 
 
 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Constexpr 
 
 
C++ 11 inseriu o constexpr, que permite que seus programas em C++ tirem 
vantagem em tempo de compilação das expressões constantes. 
Por exemplo, vamos imaginar que criemos uma função constexpr que calcule o 
fatorial e em algum ponto do código haja algo assim int fat = fatorial(5); 
Em um programa comum, o fatorial 5 serial calculado em tempo de execução, 
chamando a função e retornando seu valor, já com constexpr quando 
estivermos compilando nosso código, ele ira resolver isso, ou seja, irá calcular 
o fatorial de 5 em tempo de compilação e já vai “colocar” int fat = 120;, ou seja, 
quando estivermos executando o programa a função não será chamada, pois o 
calculo já foi feito durante a própria compilação. 
 
OBS: Constexpr só pode ter uma linha de código. 
 
#include <iostream> 
 
using namespace std; 
 
constexpr unsigned long long fatorial (int n) 
{ 
 return n > 0 ? n * fatorial( n - 1 ) : 1; 
} 
 
int main() 
{ 
 //Ira calcular em tempo de compilação sempre que possivel 
 int fat = fatorial(5); 
 
 cout << fat << '\n'; 
 
 return 0; 
} 
 
 
 
Threads 
 
Um thread executa um callable object passado como primeiro argumento de 
forma assíncrona. 
 
Exemplo 1: 
 
#include <iostream> 
#include <thread> 
#include <mutex> 
 
using namespace std; 
 
mutex mu; 
 
void threadFunc() 
{ 
 //Bloqueia cout 
 mu.lock(); 
 //Escreve em cout 
 cout << "Thread disparado.\n\n"; 
 //Libera cout 
 mu.unlock(); 
} 
 
int main() 
{ 
 int x = 10; 
 //Dispara o thread 
 thread th (threadFunc); 
 
 th.join();//sincroniza os threads para que main não termine antes de 
threadFunc(); 
 cout << "Thread main.\n" << '\n'; 
 
 return 0; 
} 
Exemplo 2 
 
#include <iostream> 
#include <thread> 
#include <windows.h> 
 
using namespace std; 
 
void pause_thread(int n) 
{ 
 //Por enquanto usaremos o sleep do windows, contido no header windows.h 
 Sleep(n); 
 std::cout << "Pausa de " << (n / 1000) << " segundos finalizada.\n"; 
} 
 
int main() 
{ 
 cout << "Disparando 3 threads de forma independente...\n"; 
 thread (pause_thread,1000).detach(); 
 thread (pause_thread,2000).detach(); 
 thread (pause_thread,3000).detach(); 
 cout << "O main thread vai parar por 5 segundos.\n\n"; 
 
 pause_thread(5000); 
 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
 
 
Uma outra forma de executar uma função de forma assíncrona é através da 
função std::async(). A vantagem é que um thread iniciado desta forma pode 
retornar um valor ou uma exceção para o thread criador. 
 
#include <iostream> 
#include <thread> 
#include <future> 
 
using namespace std; 
 
double soma(double a, double b) 
{ 
 return a+b; 
} 
 
int main() 
{ 
 auto result = std::async(soma, 10.0, 20.0); 
 
 cout << result.get() << '\n'; 
 return 0; 
} 
 
 
No exemplo anterior, uma operação assíncrona foi iniciada através da 
chamada à função std::async. Quando precisarmos do valor de retorno da 
função, usamos a função get() do objeto retornado por async(). Mas, o que o 
método async retorna ? A resposta é um objeto do tipo std::future<> que foi 
criado para esta finalidade. A chamada à função async poderia ter sido feita 
assim: 
 
#include <iostream> 
#include <thread> 
#include <future> 
 
using namespace std; 
 
double soma(double a, double b) 
{ 
 return a+b; 
} 
 
 
 
int main() 
{ 
 future<double>result = std::async(soma, 10.0, 20.0); 
 
 cout << result.get() << '\n'; 
 return 0; 
} 
 
 
Exemplo 3: 
 
#include <iostream> 
#include <thread> 
#include <future>//Pega valores de retorno de um thread 
#include <vector> 
 
using namespace std; 
 
double calculo() 
{ 
 int t = 50; 
 double result = 0; 
 
 for(int n = 0; n < t; ++n) 
 { 
 result += n; 
 } 
 cout << "Thread id: " << this_thread::get_id() << " = " << result; 
 return result; 
} 
 
int main() 
{ 
 vector<future<double>> vfuture; 
 vfuture.resize(10); 
 
 for(int n = 0; n < 10; ++n) 
 vfuture[n] = async(calculo);//assincrono 
 
 for(int n = 0; n < 10; ++n) 
 cout << " | Future:[" << n << "] = " << vfuture[n].get() << '\n'; 
 
 return 0; 
} 
Exemplo 4 
 
#include <iostream> 
#include <thread> 
#include <mutex> 
#include <future> 
#include <vector> 
 
using namespace std; 
mutex mu; 
int calculoThread = 0; 
 
int calcula() 
{ 
 this_thread::yield();//Permite a execução de varios threads 
 lock_guard<mutex>lock(mu); 
 ++calculoThread;//Para diferenciar o valor de calculo de cada thread 
 int result = 0; 
 for(int i = 0; i < (10); ++i) 
 result += i; 
 
 cout << "Resultado gerado pelo thread: " << this_thread::get_id() << ", 
resultado: " << (result + calculoThread) << '\n'; 
 return result + calculoThread; 
} 
 
int main() 
{ 
 vector<future<int>> vecFuture;//Cria vetor de future 
 vecFuture.resize(10); 
 for(int i = 0; i < 10; ++i) 
 vecFuture[i] = async(launch::async, calcula);//Os threads serão 
disparados, calculados e future vai 
 //Armazenar seu valor de retorno. 
 
 //Para dar tempo de todos os threads serem processados 
 this_thread::sleep_for(chrono::seconds(2)); 
 
 for(int i = 0; i < 10; ++i)//Capturando o valor processado pelos threads 
atraves de future 
 cout << "Pegando resultado[" << i << "]" << ", " << vecFuture[i].get() << '\n'; 
 
 return 0; 
} 
Será que a função async executou mesmo a função soma() do exemplo 
anterior de forma assíncrona? Pode ser. Isso porque neste caso, a 
implementação decide se deve iniciar a execução imediatamente, ou se é 
melhor esperar até que o método get() seja chamado para executar a função 
soma() de forma síncrona. 
Podemos escolher como executar o callableobject passando um argumento a 
mais para a função std::async(): 
auto result = std::async(std::launch::async,....); // assíncrono 
auto result = std::async(std::launch::deferred,...);// síncrono 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Mutex 
 
A execução concorrente entre threads pode ser um problema quando eles 
precisam acessar dados compartilhados entre eles. Em um determinado 
momento os threads poderão acessar simultaneamente esses dados, e obter 
resultados corrompidos. 
Para resolver esse tipo de problema, podemos usar mutex (exclusão mutual), 
que bloqueia o acesso a um recurso enquanto necessário e desbloqueia 
quando terminar. As classes disponíveis para mutex são: 
 
std::mutex 
std::timed_mutex; 
std::recursive_mutex; 
std::recursive_timed_mutex; 
Geralmente, um mutex é gerenciado por uma das classes RAII (Resource 
Acquisition is Initialization) da biblioteca padrão, são elas: 
std::lock_guard<>: Bloqueia o mutex na construtora e desbloqueia na 
destrutora. Nenhuma outra operação é permitida. 
std::unique_lock<>: Mais flexível que o std::lock_guard<>, pode adquirir o 
travamento sobre o mutex depois de construído e desbloquear antes da 
destrutora, pode ser movido,entre outras coisas. 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Mutex 
 
Não pode fazer dois locks simultâneos. 
 
#include <iostream> 
#include <thread> 
#include <mutex> 
 
using namespace std; 
 
mutex mu; 
 
void escreva() 
{ 
 for(int i = 0; i <= 10; ++i) 
 { 
 //cout esta sendo compartilhado por 2 threads e por isso devemos colocar 
o mutex aqui. 
 mu.lock(); 
 cout << "Thread: " << this_thread::get_id() << " imprimindo: " << i << '\n'; 
 //E destravar aqui. 
 mu.unlock(); 
 } 
} 
 
 
int main() 
{ 
 thread th1(&escreva), th2(&escreva); 
 
 th1.join(); 
 th2.join(); 
 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
recursive_mutex 
 
Podemos fazer dois locks simultâneos. 
 
#include <iostream> 
#include <thread> 
#include <mutex> 
 
using namespace std; 
 
recursive_mutex mu; 
 
void escreva() 
{ 
 for(int i = 0; i <= 10; ++i) 
 { 
 //cout esta sendo compartilhado por 2 threads e por isso devemos colocar 
o recursive_mutex aqui. 
 mu.lock(); 
 mu.lock(); 
 cout << "Thread: " << this_thread::get_id() << " imprimindo: " << i << '\n'; 
 //E destravar aqui. 
 mu.unlock(); 
 mu.unlock(); 
 } 
} 
int main() 
{ 
 thread th1(&escreva), th2(&escreva); 
 
 th1.join(); 
 th2.join(); 
 
 return 0; 
} 
 
 
 
 
 
 
 
 
Timed_mutex 
 
Tenta travar o mutex por um determinado tempo. 
 
#include <iostream> 
#include <thread> 
#include <mutex> 
#include <chrono> 
 
using namespace std; 
 
timed_mutex mu; 
 
void escreva() 
{ 
 auto now = std::chrono::steady_clock::now(); 
 
 for(int i = 0; i <= 10; ++i) 
 { 
 //Tenta travar por 2 segundos 
 mu.try_lock_until(now + std::chrono::seconds(2)); 
 cout << "Thread: " << this_thread::get_id() << " imprimindo: " << i << '\n'; 
 //E destravar aqui. 
 mu.unlock(); 
 } 
} 
 
int main() 
{ 
 thread th1(&escreva), th2(&escreva); 
 
 th1.join(); 
 th2.join(); 
 
 return 0; 
} 
 
 
 
 
 
 
 
 
Recursive_timed_mutex 
 
É a união de timed_mutex com recursive_mutex. 
 
#include <iostream> 
#include <thread> 
#include <mutex> 
#include <chrono> 
 
using namespace std; 
 
recursive_timed_mutex mu; 
 
void escreva() 
{ 
 auto now = std::chrono::steady_clock::now(); 
 
 for(int i = 0; i <= 10; ++i) 
 { 
 //Tenta travar por 2 segundos 
 mu.try_lock_until(now + std::chrono::seconds(2)); 
 mu.try_lock_until(now + std::chrono::seconds(2)); 
 cout << "Thread: " << this_thread::get_id() << " imprimindo: " << i << '\n'; 
 //E destravar aqui. 
 mu.unlock(); 
 mu.unlock(); 
 } 
} 
 
int main() 
{ 
 thread th1(&escreva), th2(&escreva); 
 
 th1.join(); 
 th2.join(); 
 
 return 0; 
} 
 
 
 
 
 
 
lock_guard 
 
Quando criamos um mutex corremos o risco de que haja um IF, um return, ou 
até mesmo uma exceção no meio do caminho antes de chegar no unlock, isso 
causaria dead lock no programa. 
Para evitar isso foi criado o lock_guard, que trava o mutex na construtora e 
destrava na destrutora, garantindo assim que o mutex sempre será travado e 
depois destravado. 
 
#include <iostream> 
#include <thread> 
#include <mutex> 
 
using namespace std; 
 
mutex mu; 
 
void escreva() 
{ 
 for(int i = 0; i <= 10; ++i) 
 { 
 //lock_guard travará mu na construtora 
 lock_guard<mutex> lockGuard(mu); 
 cout << "Thread: " << this_thread::get_id() << " imprimindo: " << i << '\n'; 
 } 
 //E vai destravar aqui. 
} 
 
int main() 
{ 
 thread th1(&escreva), th2(&escreva); 
 
 th1.join(); 
 th2.join(); 
 
 return 0; 
} 
 
 
 
 
 
 
 
unique_lock 
 
Nos da liberdade para destrava/travar quando quisermos, mas é garantido que 
sempre que passar pela destrutora será destravado. 
 
#include <iostream> 
#include <thread> 
#include <mutex> 
 
using namespace std; 
 
mutex mu; 
 
void escreva() 
{ 
 for(int i = 0; i <= 10; ++i) 
 { 
 //lock_guard travará mu na construtora 
 unique_lock<mutex> uniqueLock(mu); 
 cout << "Thread: " << this_thread::get_id() << " imprimindo: " << i << '\n'; 
 //Nos da liberdade para destrava/travar quando quisermos, mas é 
garantido que sempre que, 
 //passar pela destrutora será destravada. 
 uniqueLock.unlock(); 
 } 
} 
 
int main() 
{ 
 thread th1(&escreva), th2(&escreva); 
 
 th1.join(); 
 th2.join(); 
 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
Future/Promise 
 
Vimos anteriormente, que um objeto std::future<> é utilizado para pegar o valor 
retornado por uma função executada por std::async<>. Mas esta não é a única 
maneira de se disponibilizar dados para um objeto std::future<>. Podemos 
também usar um objeto std::promise<> para esta finalidade. Cada objeto 
std::promise<> esta ligado exclusivamente a um objeto std::future<>. O thread 
que tiver acesso ao objeto std::future<> pode esperar até que os dados 
estejam prontos, enquanto o thread que tem acesso ao objeto std::promise 
correspondente ao std::future<> pode chamar o método set_value() para 
disponibilizar os dados. 
 
 
Exemplo 1 
 
#include <iostream> 
#include <thread> 
#include <future> 
 
using namespace std; 
 
template<typename T> 
void ImprimeFuture(future<T> &value) 
{ 
 cout << value.get() << '\n'; 
} 
 
int main() 
{ 
 promise<int> p; 
 future<int> ft = p.get_future(); 
 thread th(ImprimeFuture<int>, ref(ft) ); 
 p.set_value(5); 
 th.join(); 
 return 0; 
} 
 
 
 
 
 
 
Exemplo 2: 
 
#include <iostream> 
#include <thread> 
#include <future> 
 
using namespace std;template<typename T> 
void ImprimeFuture(future<T> &value) 
{ 
 try 
 { 
 cout << value.get() << '\n'; 
 } 
 catch( int e ) 
 { 
 cout << "codigo do erro: " << e << endl; 
 } 
} 
 
int main() 
{ 
 promise<int> p; 
 future<int> ft = p.get_future(); 
 thread th(ImprimeFuture<int>, ref(ft) ); 
 try 
 { 
 throw 5; 
 } 
 catch(...) 
 { 
 p.set_exception( current_exception() ); 
 } 
 th.join(); 
 return 0; 
} 
 
 
 
 
 
 
 
Exemplo 3: 
 
#include <iostream> 
#include <future> 
#include <thread> 
using namespace std; 
int tarefa07() 
{ 
 return 7; 
} 
int tarefa08() 
{ 
 return 8; 
} 
int tarefa09(promise<int>& p) 
{ 
 p.set_value(9);//Estamos passando o valor 9 para o future, ou seja, quando 
fizermos f3.get(), o get ira 
 //nos retornar o 9 e não 10. 
 return 10; 
} 
int main() 
{ 
 //Cria um packaged_task para a tarefa01() 
 packaged_task<int()> task(tarefa07); 
 future<int> f1 = task.get_future(); //Pega o future do packaged_task task 
 thread(move(task)).detach(); //Dispara o thread 
 
 //future 
 future<int> f2 = async(launch::async, tarefa08); 
 
 //future com promise 
 promise<int> p; 
 future<int> f3 = p.get_future(); //Passamos o future do promise para future f3 
 thread(tarefa09 ,ref(p)).detach(); 
 
 cout << "Aguardando...\n"; 
 //Aguarda até que o resultado esteja pronto 
 f1.wait(); 
 f2.wait(); 
 f3.wait(); 
 cout << "Pronto!\nOs resultados sao: " << f1.get() << ' ' << f2.get() << ' ' << 
f3.get() << '\n'; 
} 
Neste exemplo, o thread que contém o objeto std::promise<> e que deveria 
gerar dados para o std::future<> gerou uma exceção que foi capturada e 
passada para o std::future<> através do método set_exception(). 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
packaged_task 
 
 
Um objeto packaged_task<> armazena um callable object (função, functor ou 
lambda) que será executado posteriormente. É muito semelhante a um objeto 
std::function. 
A diferença é que um objeto packaged_task<>, transfere o resultado da 
chamada ao callable object para um objeto std::future<> que pode ser usado 
por exemplo, por um outro thread. 
 
#include <future> 
#include <iostream> 
#include <thread> 
 
 
using namespace std; 
 
double soma(double a, double b) 
{ 
 return a + b; 
} 
 
void imprimesoma(future<double> &ft) 
{ 
 cout << ft.get() << '\n'; 
} 
 
int main() 
{ 
 packaged_task<double(double,double)> task(soma); 
 future<double> fd = task.get_future(); 
 
 thread th1(move(task),10.0,50.0); 
 thread th2(imprimesoma,ref(fd)); 
 
 th1.join(); 
 th2.join(); 
 return 0; 
} 
 
 
 
 
Exemplo 2: 
 
#include <iostream> 
#include <future> 
#include <thread> 
 
using namespace std; 
int tarefa07() 
{ 
 return 7; 
} 
int tarefa08() 
{ 
 return 8; 
} 
int tarefa09(promise<int>& p) 
{ 
 p.set_value(9);//Estamos passando o valor 9 para o future, ou seja, quando 
fizermos f3.get(), o get ira 
 //nos retornar o 9 e não 10. 
 return 10; 
} 
int main() 
{ 
 //Cria um packaged_task para a tarefa01() 
 packaged_task<int()> task(tarefa07); 
 future<int> f1 = task.get_future(); //Pega o future do packaged_task task 
 thread(move(task)).detach(); //Dispara o thread 
 //future 
 future<int> f2 = async(launch::async, tarefa08); 
 //future com promise 
 promise<int> p; 
 future<int> f3 = p.get_future(); //Passamos o future do promise para future f3 
 thread(tarefa09 ,ref(p)).detach(); 
 cout << "Aguardando...\n"; 
 //Aguarda até que o resultado esteja pronto 
 f1.wait(); 
 f2.wait(); 
 f3.wait(); 
 cout << "Pronto!\nOs resultados sao: " << f1.get() << ' ' << f2.get() << ' ' << 
f3.get() << '\n'; 
} 
 
Call once 
 
call_once é um template de função que através de uma variável do tipo 
once_flag controla a execução de um callable object, permitindo a execução 
deste apenas uma vez. 
 
#include <iostream> 
#include <mutex> 
 
using namespace std; 
 
once_flag flag; 
 
void f() 
{ 
 cout << "funcao f()\n"; 
} 
 
int main() 
{ 
 call_once(flag, f); 
 call_once(flag, f); 
 call_once(flag, f); 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
TLS – Thread Local Storage 
 
 
O TLS permite que cada thread tenha sua própria cópia daquela variável. A 
variável declarada com thread_local, será criada quando o thread iniciar e será 
liberada quando o thread encerrar. 
 
#include <iostream> 
#include <thread> 
 
using namespace std; 
 
thread_local int _value; 
 
void imprime_ate_20() 
{ 
 for(; _value < 20; ++_value) 
 { 
 cout << "thread " << this_thread::get_id() << ": " << _value << '\n'; 
 this_thread::yield(); 
 } 
} 
 
int main() 
{ 
 _value = 5; 
 thread th1(imprime_ate_20); 
 _value = 2; 
 thread th2(imprime_ate_20); 
 
 th1.join(); 
 th2.join(); 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
Unions 
 
 
As unions do C++11 se tornaram menos restritivas em relação ao padrão 
C++03. Mas algumas restrições permanecem: 
Não podem ser usadas em herança, nem como base e nem como derivada, 
não podem ter funções virtuais, não podem ter referências como membro, não 
podem ter membros estáticos. 
 
O que mudou: 
Podem ter objetos como membro da union 
Podem ter funções especiais (construtoras, destrutora,...) 
Podem ter membros privados 
 
#include <iostream> 
 
using namespace std; 
 
union teste 
{ 
 int n; 
 string s;//Apaga as destrutoras 
 teste(){} 
 ~teste(){} 
 void alteraDouble(double y) 
 { 
 x = y; 
 } 
 double mostraDouble() 
 { 
 return x; 
 } 
private: 
 double x; 
}; 
 
 
 
 
 
 
 
 
int main() 
{ 
 teste t; 
 
 t.n = 10; 
 cout << t.n << "\n\n"; 
 
 new (&t.s) string();//Placement new sobrecarga do operador new para 
instanciar minha string 
 t.s = "Agit"; 
 cout << t.s << "\n\n"; 
 
 
 t.alteraDouble(99.8); 
 cout << t.mostraDouble() << "\n\n"; 
 
 return 0; 
} 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Chrono 
 
 
A biblioteca chrono é utilizada para o controle do tempo. Todos os recursos 
desta biblioteca estão disponíveis através do namespace std::chrono. Chrono 
trabalha com 3 (três) conceitos principais: 
- Durações: medem um tempo que passou, por exemplo: 10 segundos, 2 
horas,etc. As durações são representadas por um objeto duration<> que se 
baseia em um contador e uma precisão do período, por exemplo, 10 é o 
contador e a precisão é segundos. 
- Pontos no tempo (time points): é a representação de um momento específico 
no tempo, por exemplo a data de nascimento, a hora do próximo trem, etc. São 
representados pelo objeto time_point<> e usa uma duração relativa a uma 
época (que é um ponto fixo no tempo comum a todos os time_points que

Continue navegando