diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 1c00c04..2991cc4 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,45 +1,7 @@ -#FROM mcr.microsoft.com/devcontainers/cpp:0-debian-11 FROM mcr.microsoft.com/devcontainers/cpp:0-ubuntu-22.04 -ARG REINSTALL_CMAKE_VERSION_FROM_SOURCE="none" - -# Optionally install the cmake for vcpkg -COPY ./reinstall-cmake.sh /tmp/ - -RUN if [ "${REINSTALL_CMAKE_VERSION_FROM_SOURCE}" != "none" ]; then \ - chmod +x /tmp/reinstall-cmake.sh && /tmp/reinstall-cmake.sh ${REINSTALL_CMAKE_VERSION_FROM_SOURCE}; \ - fi \ - && rm -f /tmp/reinstall-cmake.sh - -# [Optional] Uncomment this section to install additional vcpkg ports. -# RUN su vscode -c "${VCPKG_ROOT}/vcpkg install " - -# [Optional] Uncomment this section to install additional packages. -# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ -# && apt-get -y install --no-install-recommends - -RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ - && apt-get -y install \ - texlive texlive-base texlive-latex-extra texlive-latex-recommended \ - texlive-bibtex-extra biber \ - texlive-xetex texlive-fonts-extra \ - texlive-science \ - texlive-lang-portuguese - -# install rust -RUN curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | bash -s -- -y - -# pandoc 2.19.2 -RUN wget https://github.com/jgm/pandoc/releases/download/2.19.2/pandoc-2.19.2-1-amd64.deb -RUN sudo dpkg -i pandoc-2.19.2-1-amd64.deb - -# pandoc-crossref 0.3.13 -RUN wget https://github.com/lierdakil/pandoc-crossref/releases/download/v0.3.13.0b/pandoc-crossref-Linux.tar.xz -RUN mv pandoc-crossref-Linux.tar.xz /usr/local/bin/ -RUN (cd /usr/local/bin/ && tar xf pandoc-crossref-Linux.tar.xz) - -# install pandoc-katex -RUN bash -c 'source ~/.cargo/env; cargo install pandoc-katex' +# REFRESH! +RUN apt-get update && apt-get upgrade -y && apt-get autoremove -y # install pip (for cpplint and cmake) RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ @@ -53,56 +15,82 @@ RUN pip install --upgrade cmake RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ && apt-get -y install --no-install-recommends software-properties-common -# gcc-12 -RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ - && apt-get -y install --no-install-recommends g++-12 gcc-12 - -# clangd, clang-format and clang-tidy (standard) -#RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ -# && apt-get -y install --no-install-recommends clang-tidy clang-format clangd - -# clang-16 -RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - -RUN echo "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-16 main" >> /etc/apt/sources.list -RUN echo "deb-src http://apt.llvm.org/jammy/ llvm-toolchain-jammy-16 main" >> /etc/apt/sources.list +# clang newer +#RUN bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" +RUN curl --proto '=https' --tlsv1.2 https://apt.llvm.org/llvm.sh -sSf | bash -s -- -y # clangd, clang-format and clang-tidy RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ - && apt-get -y install --no-install-recommends clang-tidy-16 clang-format-16 clangd-16 + && apt-get -y install --no-install-recommends clang-tidy-17 clang-format-17 clangd-17 +# libc++ for clang (not using libstdc++ from gcc) RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ - && apt-get -y install --no-install-recommends lldb-16 lld-16 libc++-16-dev libc++abi-16-dev + && apt-get -y install --no-install-recommends libc++-17-dev libc++abi-17-dev + +# install gcc 13 (latest) -# =========== https://apt.llvm.org/ (Extras) ============ -# LLVM +# RUN sudo add-apt-repository ppa:ubuntu-toolchain-r/ppa -y +RUN sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ - && apt-get -y install --no-install-recommends libllvm-16-ocaml-dev libllvm16 llvm-16 llvm-16-dev llvm-16-doc llvm-16-examples llvm-16-runtime + && apt-get -y install --no-install-recommends g++-13 gcc-13 -# clang +# FORCE UPGRADE RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ - && apt-get -y install --no-install-recommends clang-16 clang-tools-16 clang-16-doc libclang-common-16-dev libclang-16-dev libclang1-16 clang-format-16 python3-clang-16 clangd-16 clang-tidy-16 + && apt-get -y upgrade # =========== -# nodejs (for bazel) -RUN curl -sL https://deb.nodesource.com/setup_18.x | sudo -E bash - -RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ - && apt-get -y install --no-install-recommends nodejs +# install nvm (for npm) +RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash +RUN bash /root/.nvm/install.sh + +# install npm (using nvm) +RUN bash -i -c "nvm install --lts" -# bazel -RUN npm install -g @bazel/bazelisk +# bazel (using npm) +RUN bash -i -c "npm install -g @bazel/bazelisk" # install cpplint into /usr/local/bin/cpplint -RUN pip install cpplint +RUN python3 -m pip install cpplint # bumpver (for versioning) RUN python3 -m pip install bumpver # default gcc-12 -RUN sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-12 10 -RUN sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 10 -# default clang-16 -RUN sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-16 10 -RUN sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-16 10 -RUN sudo update-alternatives --install /usr/bin/clangd clangd /usr/bin/clangd-16 10 -RUN sudo update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-16 10 +RUN sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 10 +RUN sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 10 +# default clang-17 +RUN sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-17 10 +RUN sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-17 10 +RUN sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-17 10 +RUN sudo update-alternatives --install /usr/bin/clangd clangd /usr/bin/clangd-17 10 +RUN sudo update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-17 10 + +# ========== begin PANDOC part =========== + +RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ + && apt-get -y install \ + texlive texlive-base texlive-latex-extra texlive-latex-recommended \ + texlive-bibtex-extra biber \ + texlive-xetex texlive-fonts-extra \ + texlive-science \ + texlive-lang-portuguese + +# install rust +RUN curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | bash -s -- -y + +# pandoc 2.19.2 +RUN wget https://github.com/jgm/pandoc/releases/download/2.19.2/pandoc-2.19.2-1-amd64.deb +RUN sudo dpkg -i pandoc-2.19.2-1-amd64.deb + +# pandoc-crossref 0.3.13 +RUN wget https://github.com/lierdakil/pandoc-crossref/releases/download/v0.3.13.0b/pandoc-crossref-Linux.tar.xz +RUN mv pandoc-crossref-Linux.tar.xz /usr/local/bin/ +RUN (cd /usr/local/bin/ && tar xf pandoc-crossref-Linux.tar.xz) + +# install pandoc-katex +RUN bash -c 'source ~/.cargo/env; cargo install pandoc-katex' + +# install pandoc-latex-fontsize +RUN python3 -m pip install pandoc-latex-fontsize + diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 337976a..e51e06a 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -5,30 +5,42 @@ "build": { "dockerfile": "Dockerfile" }, - "customizations": { "vscode": { "extensions": [ "mine.cpplint", "DevonDCarew.bazel-code", - "llvm-vs-code-extensions.vscode-clangd", "matepek.vscode-catch2-test-adapter", - ] + "ms-vscode.cmake-tools", + "llvm-vs-code-extensions.vscode-clangd", + // "-ms-vscode.cpptools-extension-pack" + ], + "settings": { + "C_Cpp.intelliSenseEngine": "disabled", + "clangd.arguments": [ + "-log=verbose", + "-pretty", + "--background-index", + "--compile-commands-dir=${workspaceFolder}/build/", + ], + "editor.formatOnSave": true, + "testMate.cpp.test.advancedExecutables": [ + { + //"pattern": "{bazel-bin}/**/*{test}*" + "pattern": "{build}/**/*{test}*" + } + ], + } } }, - // Features to add to the dev container. More info: https://containers.dev/features. // "features": {}, - // Use 'forwardPorts' to make a list of ports inside the container available locally. // "forwardPorts": [], - // Use 'postCreateCommand' to run commands after the container is created. - // "postCreateCommand": "gcc -v", - + // "postCreateCommand": "", // Configure tool-specific properties. // "customizations": {}, - // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. "remoteUser": "root" -} +} \ No newline at end of file diff --git a/slides/1-revisao-tipos/1-revisao-tipos.md b/slides/1-revisao-tipos/1-revisao-tipos.md index d6601ff..448028c 100644 --- a/slides/1-revisao-tipos/1-revisao-tipos.md +++ b/slides/1-revisao-tipos/1-revisao-tipos.md @@ -8,6 +8,9 @@ fontsize: 10 header-includes: - - +pandoc-latex-fontsize: + - classes: [cpp, listing] + size: footnotesize --- @@ -41,7 +44,7 @@ plataformas online: [onlinegdb.com/online_c++_compiler](https://www.onlinegdb.co o aluno pode escolher o compilador de C ou da linguagem C++ (considerando padrão C++20). -# Tipos em C/C++ +# Parte 1: Tipos Primitivos, Vetores, Agregados, Tipos Genéricos e Ponteiros em C/C++ ------ @@ -74,15 +77,15 @@ float z = 3.7 ; // armazena o real 3.7 na variável z **Pergunta/Resposta**: Cuidado com tipos. Quais são os valores armazenados nas variáveis abaixo (C++)? -```.cpp +```{.cpp .listing} int x1 = 5; // => 5 -int x2 = x1 + 8; // => 13 -int x3 = x2 / 2; // => 6 -float x4 = x2 / 2; // => 6.0 -float x5 = x2 / 2.0; // => 6.5 -auto x6 = 13; // => 13 (C warning: Wimplicit-int) -auto x7 = x2 / 2; // => ? (C warning: Wimplicit-int) -auto x8 = x2 / 2.0; // => ? (C warning: Wimplicit-int) +int x2 = x1 + 10; // => 15 +int x3 = x2 / 2; // => 7 +float x4 = x2 / 2; // => 7.0 +float x5 = x2 / 2.0; // => 7.5 +auto x6 = 15; // => 15 (C warning: Wimplicit-int) +auto x7 = x2 / 2; // => ? (C warning: Wimplicit-int) +auto x8 = x2 / 2.0; // => ? (C warning: Wimplicit-int) ``` Verifiquem essas operações de variáveis, escrevendo na saída padrão (tela do computador). @@ -109,16 +112,14 @@ ao invés de indireta por atribuição (`operator=`). ------ - ## Impressão de Saída Padrão Para imprimir na saída padrão utilizaremos o comando `print`. Em C, tipicamente é utilizado o comando `printf`, mas devido a inúmeras falhas de segurança, é recomendado o uso de uma alternativa mais segura. -O C++20 traz o header ``, que é suficiente para implementar o `print`, -mas somente o C++23 traz o header `` com método oficial `std::print`. -Então utilizaremos o comando `fmt::print`, da biblioteca ``, +Somente o C++23 traz oficialmente o header `` com método oficial `std::print`. +Então podemos utilizar o comando `fmt::print`, da biblioteca ``, ao invés do `std::print`, ainda indisponível no C++20. ```.cpp @@ -135,6 +136,29 @@ int main() { ## Impressão de Saída Padrão +Tomando vantagem do padrão C++20 com o header `` +é possível implementar uma versão simplificada do `print` +(sem depender de bibliotecas externas como `fmt::print`). +Uma possível solução utilizando macros de C é (tome cuidado +com possíveis efeitos indesejados de macros): + +```.cpp +#include + +// Solution using __VA_ARGS__ and VA_OPT (## from c++20) +#define print(fmt, ...) \ + printf("%s", std::format(fmt, ##__VA_ARGS__).c_str()) + +int main() { + print("olá mundo!\n"); + return 0; +} +``` + +------ + +## Impressão de Saída Padrão + Para imprimir na saída padrão utilizaremos o comando `fmt::print`. Este comando é dividido em duas partes, sendo que na primeira colocamos a mensagem formatada e, a seguir, colocamos as variáveis cujo diff --git a/slides/1-revisao-tipos/1-revisao-tipos.pdf b/slides/1-revisao-tipos/1-revisao-tipos.pdf index df576be..0fe48b2 100644 Binary files a/slides/1-revisao-tipos/1-revisao-tipos.pdf and b/slides/1-revisao-tipos/1-revisao-tipos.pdf differ diff --git a/slides/1-revisao-tipos/header.tex b/slides/1-revisao-tipos/header.tex index 73c57f7..3ae3bb4 100644 --- a/slides/1-revisao-tipos/header.tex +++ b/slides/1-revisao-tipos/header.tex @@ -38,8 +38,8 @@ \usepackage[ruled,vlined,linesnumbered]{algorithm2e} - - +%\usepackage{listings} +%\renewenvironment{Shaded} {\begin{snugshade}\footnotesize} {\end{snugshade}} %write file with 7 predefined 3D views \usepackage{filecontents} diff --git a/slides/1-revisao-tipos/index.html b/slides/1-revisao-tipos/index.html index d496da1..ae62410 100644 --- a/slides/1-revisao-tipos/index.html +++ b/slides/1-revisao-tipos/index.html @@ -523,8 +523,9 @@

Ambiente de Programação

(considerando padrão C++20).

-
-

Tipos em C/C++

+
+

Parte 1: Tipos Primitivos, Vetores, Agregados, Tipos Genéricos e +Ponteiros em C/C++

@@ -546,14 +547,14 @@

Conceitos de C/C++

Tipos de Variáveis

Pergunta/Resposta: Cuidado com tipos. Quais são os valores armazenados nas variáveis abaixo (C++)?

-
int    x1 = 5;        // => 5
-int    x2 = x1 + 8;   // => 13
-int    x3 = x2 / 2;   // => 6
-float  x4 = x2 / 2;   // => 6.0
-float  x5 = x2 / 2.0; // => 6.5
-auto   x6 = 13;       // => 13 (C warning: Wimplicit-int)
-auto   x7 = x2 / 2;   // => ?  (C warning: Wimplicit-int)
-auto   x8 = x2 / 2.0; // => ?  (C warning: Wimplicit-int)
+
int    x1 = 5;        // => 5
+int    x2 = x1 + 10;  // => 15
+int    x3 = x2 / 2;   // => 7
+float  x4 = x2 / 2;   // => 7.0
+float  x5 = x2 / 2.0; // => 7.5
+auto   x6 = 15;       // => 15   (C warning: Wimplicit-int)
+auto   x7 = x2 / 2;   // => ?    (C warning: Wimplicit-int)
+auto   x8 = x2 / 2.0; // => ?    (C warning: Wimplicit-int)

Verifiquem essas operações de variáveis, escrevendo na saída padrão (tela do computador).

@@ -576,10 +577,9 @@

Impressão de Saída Padrão

print. Em C, tipicamente é utilizado o comando printf, mas devido a inúmeras falhas de segurança, é recomendado o uso de uma alternativa mais segura.

-

O C++20 traz o header <format>, que é suficiente -para implementar o print, mas somente o C++23 traz o header -<print> com método oficial std::print. -Então utilizaremos o comando fmt::print, da biblioteca +

Somente o C++23 traz oficialmente o header <print> +com método oficial std::print. Então podemos utilizar o +comando fmt::print, da biblioteca <fmt/core.h>, ao invés do std::print, ainda indisponível no C++20.

#include <fmt/core.h>
@@ -592,6 +592,24 @@ 

Impressão de Saída Padrão

Impressão de Saída Padrão

+

Tomando vantagem do padrão C++20 com o header +<format> é possível implementar uma versão +simplificada do print (sem depender de bibliotecas externas +como fmt::print). Uma possível solução utilizando macros de +C é (tome cuidado com possíveis efeitos indesejados de macros):

+
#include <format>
+
+// Solution using __VA_ARGS__ and VA_OPT (## from c++20)
+#define print(fmt, ...) \
+  printf("%s", std::format(fmt, ##__VA_ARGS__).c_str())
+
+int main() {
+   print("olá mundo!\n");
+   return 0;
+}
+
+
+

Impressão de Saída Padrão

Para imprimir na saída padrão utilizaremos o comando fmt::print. Este comando é dividido em duas partes, sendo que na primeira colocamos a mensagem formatada e, a seguir, colocamos as @@ -602,37 +620,37 @@

Impressão de Saída Padrão

Resposta: através do padrão de substituição {}.

-
  int32_t x1 = 7;
-  print("x1 é {}", x1);  // x1 é 7
-  float x6 = x1 / 2.0;
-  print("metade de {} é {}", x1, x6);  // metade de 7 é 3.5
-  char b = 'L';
-  print("isto é uma {}etra", b);  // isto é uma Letra
-  print("Olá mundo! \n");  // Olá mundo! (quebra de linha)
+
  int32_t x1 = 7;
+  print("x1 é {}", x1);  // x1 é 7
+  float x6 = x1 / 2.0;
+  print("metade de {} é {}", x1, x6);  // metade de 7 é 3.5
+  char b = 'L';
+  print("isto é uma {}etra", b);  // isto é uma Letra
+  print("Olá mundo! \n");  // Olá mundo! (quebra de linha)

Condicionais e Laços de Repetição

Condicionais podem ser feitos através dos comandos if ou if else.

-
int x = 12;
-if (x > 10)
-   print("x maior de 10\n");
-else
-   print("x menor ou igual a 10\n");
+
int x = 12;
+if (x > 10)
+   print("x maior de 10\n");
+else
+   print("x menor ou igual a 10\n");

Laços de repetição podem ser feitos através de comandos while ou for. Um comando for é dividido em três partes: inicialização, condição de continuação e incremento.

-
for (auto i=0; i < 10 ; i++) {
-   print("i : {}\n" , i);
-}
+
for (auto i=0; i < 10 ; i++) {
+   print("i : {}\n" , i);
+}
-
auto j=0;
-while (j < 10) {
-   print("j : {}\n", j);
-   j++;
-}
+
auto j=0;
+while (j < 10) {
+   print("j : {}\n", j);
+   j++;
+}
@@ -647,31 +665,31 @@

Controle de fluxo com break e z):

-
int z = 0;
-int i = 0;
-for (; i < 10; i++) {
-   if (i > 5) continue;
-   print("z={} i={}\n", 
-          z, i);
-   z++;
-}
-//
-// z==6  i==10
-print("final z={} i={}\n", 
-       z, i);
-
int z = 0;
 int i = 0;
-while (i < 10) {
-   print("z={} i={}\n", 
-          z, i);
-   z++;
-   if (i > 5) break;
-   i++;
-}
-// z==7  i==6
+for (; i < 10; i++) {
+   if (i > 5) continue;
+   print("z={} i={}\n", 
+          z, i);
+   z++;
+}
+//
+// z==6  i==10
 print("final z={} i={}\n", 
        z, i);
+
+
int z = 0;
+int i = 0;
+while (i < 10) {
+   print("z={} i={}\n", 
+          z, i);
+   z++;
+   if (i > 5) break;
+   i++;
+}
+// z==7  i==6
+print("final z={} i={}\n", 
+       z, i);

@@ -685,17 +703,17 @@

Saltos incondicionais com goto

else, break, etc.

Contabilize quantos prints são executados (variável z):

-
  int z = 0;
-  for (auto i = 0; i < 10; i++) {
-    if (i < 5) continue; int j = i;
-    while (j < 10) {
-      if (i > 6) goto fim;
-      print("z={} i={} j={}\n", z, i, j); z++; j++;
-    }
-  }
-fim:
-  // z==9: i=5 j=5..9 [5 passos]; i=6 j=6..9 [4 passos]
-  print("final z={}\n", z);
+
  int z = 0;
+  for (auto i = 0; i < 10; i++) {
+    if (i < 5) continue; int j = i;
+    while (j < 10) {
+      if (i > 6) goto fim;
+      print("z={} i={} j={}\n", z, i, j); z++; j++;
+    }
+  }
+fim:
+  // z==9: i=5 j=5..9 [5 passos]; i=6 j=6..9 [4 passos]
+  print("final z={}\n", z);

Tipos Compostos

@@ -706,9 +724,9 @@

Tipos Compostos

Os tipos compostos podem ser vetores (arrays) ou agregados (structs, …).

-
int32_t v[8]; // cria um vetor com 8 inteiros
-v[0] = 3;     // atribui o valor 3 à primeira posição
-v[7] = 5;     // atribui o valor 5 à última posição
+
int32_t v[8]; // cria um vetor com 8 inteiros
+v[0] = 3;     // atribui o valor 3 à primeira posição
+v[7] = 5;     // atribui o valor 5 à última posição
          v: | 3 |   |   |   |   |   |   | 5 |
                0   1   2   3   4   5   6   7
@@ -721,29 +739,29 @@

Tipos Agregados I

forma completamente diferente na linguagem C++):

-
// Em C (tipo agregado P)
-struct P
-{
-    int32_t x;
-    char y;
-};
-
-// declara variável tipo P
-struct P p1;
-// designated initializers
-struct P p2 = {.x=10, .y='Y'};
-
-
// Em C++ (tipo agregado P)
-class P
+
// Em C (tipo agregado P)
+struct P
 {
-public:
-    int32_t x;
-    char y;
-};
+    int32_t x;
+    char y;
+};
+
 // declara variável tipo P
-P p1;
+struct P p1;
 // designated initializers
-auto p2 = P{.x=10, .y='Y'};
+struct P p2 = {.x=10, .y='Y'};
+
+
// Em C++ (tipo agregado P)
+class P
+{
+public:
+    int32_t x;
+    char y;
+};
+// declara variável tipo P
+P p1;
+// designated initializers
+auto p2 = P{.x=10, .y='Y'};
@@ -754,11 +772,11 @@

Tipos Agregados II

Assim como na inicialização designada, podemos utilizar o operador ponto (.) para acessar campos do agregado.

Exemplo:

-
auto p1 = P{.y = 'A'};
-
-p1.x = 20;             // atribui 20 à variável x de p1
-p1.x = p1.x + 1;       // incrementa a variável x de p1
-print("{} {}\n", p1.x, p1.y);  // imprime '21 A'
+
auto p1 = P{.y = 'A'};
+
+p1.x = 20;             // atribui 20 à variável x de p1
+p1.x = p1.x + 1;       // incrementa a variável x de p1
+print("{} {}\n", p1.x, p1.y);  // imprime '21 A'
             p1:  |      21       | 'A' |
                         p1.x        p1.y
@@ -769,9 +787,9 @@

Espaço de Memória

float) ocupa 4 bytes, enquanto um char ocupa apenas 1 byte.

No caso de vetores, o espaço ocupado na memória é multiplicado pelo número de elementos. Vamos calcular o espaço das variáveis:

-
int32_t v[256]; // = 1024 bytes = 1 kibibyte = 1 KiB
-char x[1000];   // = 1000 bytes = 1 kilobyte = 1 kB
-float y[5];     // = 20 bytes
+
int32_t v[256]; // = 1024 bytes = 1 kibibyte = 1 KiB
+char x[1000];   // = 1000 bytes = 1 kilobyte = 1 kB
+float y[5];     // = 20 bytes

Já nos agregados, assumimos o espaço ocupado como a soma de suas variáveis internas (embora na prática o tamanho possa ser ligeiramente superior, devido a alinhamentos de memória).

@@ -782,16 +800,16 @@

Tipos Genéricos

permitem que algum outro tipo seja passado como parâmetro.

Consideremos o agregado P que carrega um int e um char… como transformá-lo em um agregado genérico em relação à variável x?

-
template<typename T>
-class G
-{
-public:
-   T x;   // qual o tipo da variável x?
-   char y;
-};
-// declara o agregado genérico G
-G<float> g1 = {.x = 3.14, .y  = 'Y'};
-G<int>   g2 = {.x = 3,    .y  = 'Y'};
+
template<typename T>
+class G
+{
+public:
+   T x;   // qual o tipo da variável x?
+   char y;
+};
+// declara o agregado genérico G
+G<float> g1 = {.x = 3.14, .y  = 'Y'};
+G<int>   g2 = {.x = 3,    .y  = 'Y'};

Valores constantes e casts

@@ -799,19 +817,19 @@

Valores constantes e casts

const. Uma mudança de tipos pode ser feita com type cast. Em C++, utilize static_cast<tipo> ao invés do padrão C de cast.

-
unsigned int x = 10;
-int y1 = (int) x;             // em C
-int y2 = int(x);              // em C
-int y3 = static_cast<int>(x); // em C++
-const unsigned int z1 = x;    // OK
-// unsigned int z2 = z1;      // ERRO
+
unsigned int x = 10;
+int y1 = (int) x;             // em C
+int y2 = int(x);              // em C
+int y3 = static_cast<int>(x); // em C++
+const unsigned int z1 = x;    // OK
+// unsigned int z2 = z1;      // ERRO

O const pode ser removido em algumas circustâncias através de um const_cast. Em C++, existe também o constexpr, que diferentemente do const, nunca pode ser removido, pois é de tempo de compilação. Em C, algo similar é possível com macros, mas permite reescrita, sendo inseguro.

-
#define k1 10          // C (inseguro e permite redefinição)
-constexpr int k2 = 10; // C++ (seguro, impossível redefinir)
+
#define k1 10          // C (inseguro e permite redefinição)
+constexpr int k2 = 10; // C++ (seguro, impossível redefinir)

Resumo até agora

@@ -834,29 +852,29 @@

Rotinas I

procedimentos, que podem por sua vez receber parâmetros.

Tomemos por exemplo a função quadrado que retorna o valor passado elevado ao quadrado.

-
// função que retorna um 'int', com parâmetro 'p'
-int quadrado (int p) {
-   return p*p;
-}
-// variável do tipo 'int', com valor 25
-int x = quadrado(5);        
+
// função que retorna um 'int', com parâmetro 'p'
+int quadrado (int p) {
+   return p*p;
+}
+// variável do tipo 'int', com valor 25
+int x = quadrado(5);        

Rotinas II

Quando nenhum valor é retornado (em um procedimento), utilizamos a palavra-chave void. Procedimentos são úteis mesmo quando nenhum valor é retornado. Exemplo: (de a até b):

-
void imprime (int a , int b) {
-   for (auto i=a ; i<b ; i++)
-      print("{}\n", i) ;
-}
+
void imprime (int a , int b) {
+   for (auto i=a ; i<b ; i++)
+      print("{}\n", i) ;
+}

Também é possível retornar múltiplos elementos (par ou tupla), através de um structured binding (requer #include<tuple>):

-
auto duplo(int p) {
-   return std::make_tuple(p+3, p+6);
-}
-auto [x1,x2] = duplo(10); // x1=13 x2=16
+
auto duplo(int p) {
+   return std::make_tuple(p+3, p+6);
+}
+auto [x1,x2] = duplo(10); // x1=13 x2=16

Ponteiros I

@@ -880,17 +898,17 @@

Ponteiros II

Em ponteiros para agregados, o operador de acesso (.) é substituído por uma seta (->). O operador & toma o endereço da variável:

-
struct P {
-   int32_t x;
-   char y;
-};
-
-void imprimir(struct P* p1, struct P p2) {
-   print("{} {}\n", p1->x, p2.x);
-}
-// ...
-struct P p0 = {.x = 20, .y = 'Y'}; // cria variável 'p0'
-imprimir(&p0, p0); // resulta em '20 20'
+
struct P {
+   int32_t x;
+   char y;
+};
+
+void imprimir(struct P* p1, struct P p2) {
+   print("{} {}\n", p1->x, p2.x);
+}
+// ...
+struct P p0 = {.x = 20, .y = 'Y'}; // cria variável 'p0'
+imprimir(&p0, p0); // resulta em '20 20'

Alocação Dinâmica de Memória

@@ -899,26 +917,26 @@

Alocação Dinâmica de Memória

memória:

-
// Aloca (C) o agregado P
-struct P* vp =
-   malloc(1*sizeof(struct P));
-// inicializa campos de P
-vp->x = 10;
-vp->y = 'Y';
-// imprime x (valor 10)
-print("{}\n", vp->x);
-// descarta a memória
-free(vp);
+
// Aloca (C) o agregado P
+struct P* vp =
+   malloc(1*sizeof(struct P));
+// inicializa campos de P
+vp->x = 10;
+vp->y = 'Y';
+// imprime x (valor 10)
+print("{}\n", vp->x);
+// descarta a memória
+free(vp);
-
// Aloca (C++) o agregado P
-auto* vp = new P{
-                  .x = 10,
-                  .y = 'Y'
-                };
-// imprime x (valor 10)
-print("{}\n", vp->x);
-// descarta a memória
-delete vp;
+
// Aloca (C++) o agregado P
+auto* vp = new P{
+                  .x = 10,
+                  .y = 'Y'
+                };
+// imprime x (valor 10)
+print("{}\n", vp->x);
+// descarta a memória
+delete vp;
@@ -928,26 +946,26 @@

Rotinas III

localização desta função na memória do computador. Por exemplo:

-
// tipo: int(*)(int)
-int quadrado(int p) {
-   return p*p;      
-}
-
-
// tipo: float(*)(int)
-auto fquad(int p) -> float{
+
// tipo: int(*)(int)
+int quadrado(int p) {
    return p*p;      
 }
+
+
// tipo: float(*)(int)
+auto fquad(int p) -> float{
+   return p*p;      
+}

Este fato pode ser útil para receber funções como parâmetro, bem como armazenar funções anônimas (lambdas):

-
// armazena lambda no ponteiro de função 'quad'
-int(*quad)(int) = [](int p) -> int {
-                     return p*p;
-                  };
-print("{}\n", quad(3)); // 9
-// ou, utilizando 'auto' para deduzir o tipo
-auto func = [](int p) { return p*p; };
+
// armazena lambda no ponteiro de função 'quad'
+int(*quad)(int) = [](int p) -> int {
+                     return p*p;
+                  };
+print("{}\n", quad(3)); // 9
+// ou, utilizando 'auto' para deduzir o tipo
+auto func = [](int p) { return p*p; };

Rotinas IV

@@ -957,27 +975,27 @@

Rotinas IV

agregado, chamado this:

-
// Em C (tipo agregado Z)
-struct Z {
-    int x;
-};
-
-// imprime campo x
-void imprimex(struct Z* this)
-{
-   print("{}\n", this->x);
-}
+
// Em C (tipo agregado Z)
+struct Z {
+    int x;
+};
+
+// imprime campo x
+void imprimex(struct Z* this)
+{
+   print("{}\n", this->x);
+}
-
// Em C++ (tipo agregado Z)
-class Z
-{
-public:
-   int x;
-   // imprime campo x
-   void imprimex() {
-      print("{}\n", this->x);
-   }
-};
+
// Em C++ (tipo agregado Z)
+class Z
+{
+public:
+   int x;
+   // imprime campo x
+   void imprimex() {
+      print("{}\n", this->x);
+   }
+};
@@ -994,24 +1012,24 @@

Ponteiros III

std::make_unique ou std::make_shared.

-
// Aloca (C++) o agregado P
-auto* vp = new P{
-                  .x = 10,
-                  .y = 'Y'
-                };
-// imprime x (valor 10)
-print("{}\n", vp->x);
-// descarta a memória
-delete vp;
+
// Aloca (C++) o agregado P
+auto* vp = new P{
+                  .x = 10,
+                  .y = 'Y'
+                };
+// imprime x (valor 10)
+print("{}\n", vp->x);
+// descarta a memória
+delete vp;
-
// Aloca (C++) o agregado P
-auto vp = 
-   std::make_unique<P>(
-     P{.x = 10, .y = 'Y'});
-// imprime x (valor 10)
-print("{}\n", vp->x);
-// descarta a memória
-// delete vp;
+
// Aloca (C++) o agregado P
+auto vp = 
+   std::make_unique<P>(
+     P{.x = 10, .y = 'Y'});
+// imprime x (valor 10)
+print("{}\n", vp->x);
+// descarta a memória
+// delete vp;
@@ -1028,25 +1046,25 @@

Ponteiros IV

NULL e std::nullptr.

-
// Aloca (C++) o agregado P
-auto* vp = new P{
-                  .x = 10,
-                  .y = 'Y'
-                };
-if(vp)  print("sucesso!\n");
-if(!vp)      print("falha!\n");
-if(vp==NULL) print("falha!\n");
-if(vp==0)    print("falha!\n");
+
// Aloca (C++) o agregado P
+auto* vp = new P{
+                  .x = 10,
+                  .y = 'Y'
+                };
+if(vp)  print("sucesso!\n");
+if(!vp)      print("falha!\n");
+if(vp==NULL) print("falha!\n");
+if(vp==0)    print("falha!\n");
-
// Aloca (C++) o agregado P
-auto vp = 
-   std::make_unique<P>(
-     P{.x = 10, .y = 'Y'});
-if(vp)  print("sucesso!\n");
-if(!vp) print("falha!\n");
-
-// reseta manualmente
-vp = std::nullptr;
+
// Aloca (C++) o agregado P
+auto vp = 
+   std::make_unique<P>(
+     P{.x = 10, .y = 'Y'});
+if(vp)  print("sucesso!\n");
+if(!vp) print("falha!\n");
+
+// reseta manualmente
+vp = std::nullptr;
@@ -1058,18 +1076,18 @@

Conceitos I

Por exemplo, podemos criar um conceito TemImprimeX, que exige que o agregado possua um método imprimex():

-
template <typename Agregado>
-concept TemImprimeX = requires(Agregado a) {
-  { a.imprimex() };
-};
+
template <typename Agregado>
+concept TemImprimeX = requires(Agregado a) {
+  { a.imprimex() };
+};

Conceitos II

Assim, podemos utilizar um conceito mais específico ao invés de um tipo automático:

-
auto a1             = Z{.x = 1};  // tipo automático
-TemImprimeX auto a2 = Z{.x = 2};  // tipo conceitual
-Z a3                = Z{.x = 3};  // tipo explícito
+
auto a1             = Z{.x = 1};  // tipo automático
+TemImprimeX auto a2 = Z{.x = 2};  // tipo conceitual
+Z a3                = Z{.x = 3};  // tipo explícito

Importante: a noção de conceitos é fundamental para a compreensão de tipos abstratos, central no curso de estruturas de dados.

@@ -1088,41 +1106,41 @@

Passagem de Parâmetros por Referência I

não permitem cópias, sendo obrigatoriamente passados por referência.

Para transformar uma variável viva para uma variável em movimento, basta usar o comando std::move.

-
auto p1 = std::make_unique<P>(P{.x = 10, .y = 'Y'});
-print("{}\n", p1->x); // imprime x (valor 10)
-auto p2 = std::move(p1);
-if(!p1) print("p1 não existe mais!\n");
-print("{}\n", p2->x); // imprime x (valor 10)
+
auto p1 = std::make_unique<P>(P{.x = 10, .y = 'Y'});
+print("{}\n", p1->x); // imprime x (valor 10)
+auto p2 = std::move(p1);
+if(!p1) print("p1 não existe mais!\n");
+print("{}\n", p2->x); // imprime x (valor 10)

Passagem de Parâmetros por Referência II

-
// C++
-void imprimex(P* vp) {
-  // imprime x (valor 10)
-  print("{}\n", vp->x);
-}
-// ...
-auto p = P{
-         .x = 10,
-         .y = 'Y'
-         };
-// cópia de ponteiro
-imprimex(&p);
-
-
// C++
-void imprimex(P& vp) {
+
// C++
+void imprimex(P* vp) {
   // imprime x (valor 10)
-  print("{}\n", vp.x);
+  print("{}\n", vp->x);
 }
 // ...
 auto p = P{
          .x = 10,
          .y = 'Y'
          };
-// referência (lvalue)
-imprimex(p);
+// cópia de ponteiro +imprimex(&p);
+
+
// C++
+void imprimex(P& vp) {
+  // imprime x (valor 10)
+  print("{}\n", vp.x);
+}
+// ...
+auto p = P{
+         .x = 10,
+         .y = 'Y'
+         };
+// referência (lvalue)
+imprimex(p);
@@ -1132,31 +1150,31 @@

Passagem de Parâmetros por Referência III

referências de lado direito (rvalue). Observe:

-
void teste1(int x) { 
-   x = 10; 
-}
-void teste2(int* x) { 
-   *x = 10; 
-}
-void teste3(int& x) { 
-   x = 10; 
-}
-void teste4(int&& x) { 
-   x = 10; 
-}
+
void teste1(int x) { 
+   x = 10; 
+}
+void teste2(int* x) { 
+   *x = 10; 
+}
+void teste3(int& x) { 
+   x = 10; 
+}
+void teste4(int&& x) { 
+   x = 10; 
+}
-
int a = 20;
-teste1(a);     // a == 20
-teste2(&a);    // a <- 10
-teste3(a);     // a <- 10
-// teste4(a);  // ERRO
-teste4(std::move(a)); // OK
-// supostamente a <- 10
-
-teste1(20);     // OK
-// teste2(20);  // ERRO
-// teste3(20);  // ERRO
-teste4(20);     // OK
+
int a = 20;
+teste1(a);     // a == 20
+teste2(&a);    // a <- 10
+teste3(a);     // a <- 10
+// teste4(a);  // ERRO
+teste4(std::move(a)); // OK
+// supostamente a <- 10
+
+teste1(20);     // OK
+// teste2(20);  // ERRO
+// teste3(20);  // ERRO
+teste4(20);     // OK

Observação: existe também a sintaxe @@ -1194,16 +1212,16 @@

Tipo std::string

char*, char[] ou const char* em C. Para utilizar, basta fazer #include <string>. Exemplo:

-
std::string s1 = "abcd";
-std::string s2 = "ef";
-print("tamanho1={} tamanho2={}\n", s1.length(), s2.length());
-// tamanho1=4 tamanho2=2
-s1 = s1 + s2;
-print("s1={} s2={}\n", s1, s2);
-// s1=abcdef s2=ef
-const char* cs = s1.c_str();
-print("s1={} cs={}\n", s1, cs);
-// s1=abcdef cs=abcdef
+
std::string s1 = "abcd";
+std::string s2 = "ef";
+print("tamanho1={} tamanho2={}\n", s1.length(), s2.length());
+// tamanho1=4 tamanho2=2
+s1 = s1 + s2;
+print("s1={} s2={}\n", s1, s2);
+// s1=abcdef s2=ef
+const char* cs = s1.c_str();
+print("s1={} cs={}\n", s1, cs);
+// s1=abcdef cs=abcdef

Tipo std::array

@@ -1211,19 +1229,19 @@

Tipo std::array

std::array<tipo, tamanho> permite representar vetores de tamanho fixo. Para utilizar, basta fazer #include <array>. Exemplo:

-
int v1[10];
-int v2[] = {1, 2, 3, 4};
-std::array<int, 10> a1{};
-std::array<int, 4> a2 = {1, 2, 3, 4};
-print("v[0]={} v[3]={} tam={}\n", v2[0], v2[3],
-      sizeof(v2) / sizeof(v2[0]));
-// v[0]=1 v[3]=4 tam=4
-print("a[0]={} a[3]={} tam={}\n", a2[0], a2[3], a2.size());
-// a[0]=1 a[3]=4 tam=4
-print("{} {} {}\n", std::is_aggregate<int*>::value,
-      std::is_aggregate<int[]>::value,
-      std::is_aggregate<std::array<int, 4>>::value);
-// false true true
+
int v1[10];
+int v2[] = {1, 2, 3, 4};
+std::array<int, 10> a1{};
+std::array<int, 4> a2 = {1, 2, 3, 4};
+print("v[0]={} v[3]={} tam={}\n", v2[0], v2[3],
+      sizeof(v2) / sizeof(v2[0]));
+// v[0]=1 v[3]=4 tam=4
+print("a[0]={} a[3]={} tam={}\n", a2[0], a2[3], a2.size());
+// a[0]=1 a[3]=4 tam=4
+print("{} {} {}\n", std::is_aggregate<int*>::value,
+      std::is_aggregate<int[]>::value,
+      std::is_aggregate<std::array<int, 4>>::value);
+// false true true

Tipo std::vector

@@ -1231,19 +1249,19 @@

Tipo std::vector

representar vetores com tamanho variável (através do método push_back). Para utilizar, basta fazer #include <vector>. Exemplo:

-
int v1[10];
-int v2[] = {1, 2, 3, 4};
-std::vector<int> k1{};
-std::vector<int> k2 = {1, 2, 3, 4};
-k2.push_back(999);
-//
-print("v[0]={} v[3]={} tam={}\n", v2[0], v2[3], 
-      sizeof(v2) / sizeof(v2[0]));
-// v[0]=1 v[3]=4 tam=4
-print("k[0]={} k[4]={} tam={}\n", k2[0], k2[4], k2.size());
-// k[0]=1 k[4]=999 tam=5
-print("{}\n", std::is_aggregate<std::vector<int>>::value);
-// false
+
int v1[10];
+int v2[] = {1, 2, 3, 4};
+std::vector<int> k1{};
+std::vector<int> k2 = {1, 2, 3, 4};
+k2.push_back(999);
+//
+print("v[0]={} v[3]={} tam={}\n", v2[0], v2[3], 
+      sizeof(v2) / sizeof(v2[0]));
+// v[0]=1 v[3]=4 tam=4
+print("k[0]={} k[4]={} tam={}\n", k2[0], k2[4], k2.size());
+// k[0]=1 k[4]=999 tam=5
+print("{}\n", std::is_aggregate<std::vector<int>>::value);
+// false

Tipo std::optional

@@ -1251,19 +1269,19 @@

Tipo std::optional

opcional, com alocação em stack, não em heap como smart pointers. Para utilizar, basta fazer #include <optional>. Exemplo:

-
std::optional<int> busca(char c, const std::vector<char>& v) {
-  // busca char 'c' num vetor v e retorna posição
-  for(int i=0; i<static_cast<int>(v.size()); i++)
-     if(v[i] == c)
-        return i; // encontrou
-  // não encontrou
-  return std::nullopt;
-}
-// ...
-std::vector<char> v = {'a', 'b', 'c'};
-auto op = busca('x', v);
-if(op) print("posicao={}", *op);
-else   print("não encontrou");
+
std::optional<int> busca(char c, const std::vector<char>& v) {
+  // busca char 'c' num vetor v e retorna posição
+  for(int i=0; i<static_cast<int>(v.size()); i++)
+     if(v[i] == c)
+        return i; // encontrou
+  // não encontrou
+  return std::nullopt;
+}
+// ...
+std::vector<char> v = {'a', 'b', 'c'};
+auto op = busca('x', v);
+if(op) print("posicao={}", *op);
+else   print("não encontrou");

Tipo std::unique_ptr

@@ -1272,18 +1290,18 @@

Tipo std::unique_ptr

função útil é o get, que retorna um ponteiro nativo C para o dado. A função reset apaga o ponteiro manualmente. Para utilizar, basta fazer #include <memory>. Exemplo:

-
auto* p1 = new int{10};
-auto* p2 = p1;
-print("*p1={} *p2={}\n", *p1, *p2);
-// *p1=10 *p2=10
-delete p1;
-
-auto u1 = std::make_unique<int>(10);
-auto u2 = std::move(u1);
-auto* p3 = u2.get();
-print("*u2={} *p3={}\n", *u2, *p3);
-// *u2=10 *p3=10
-u2.reset(); // apaga ponteiro u2 manualmente
+
auto* p1 = new int{10};
+auto* p2 = p1;
+print("*p1={} *p2={}\n", *p1, *p2);
+// *p1=10 *p2=10
+delete p1;
+
+auto u1 = std::make_unique<int>(10);
+auto u2 = std::move(u1);
+auto* p3 = u2.get();
+print("*u2={} *p3={}\n", *u2, *p3);
+// *u2=10 *p3=10
+u2.reset(); // apaga ponteiro u2 manualmente

Tipo std::shared_ptr

@@ -1297,14 +1315,14 @@

Tipo std::shared_ptr

std::weak_ptr ou cycles::relation_ptr (a seguir). Para utilizar, basta fazer #include <memory>. Exemplo:

-
auto s1 = std::make_shared<int>(10);
-auto s2 = s1;
-std::weak_ptr<int> w1 = s1;
-auto s3 = w1.lock();
-print("*s1={} *s2={} *s3={}\n", *s1, *s2, *s3);
-// *s1=10 *s2=10 *s3=10
-s1.reset(); // apaga ponteiro s1 manualmente
-print("*s2={} *s3={} ainda existem!\n", *s2, *s3);
+
auto s1 = std::make_shared<int>(10);
+auto s2 = s1;
+std::weak_ptr<int> w1 = s1;
+auto s3 = w1.lock();
+print("*s1={} *s2={} *s3={}\n", *s1, *s2, *s3);
+// *s1=10 *s2=10 *s3=10
+s1.reset(); // apaga ponteiro s1 manualmente
+print("*s2={} *s3={} ainda existem!\n", *s2, *s3);

Tipo std::function

@@ -1315,17 +1333,17 @@

Tipo std::function

enquanto as demais só podem ser encapsuladas como std::function. Basta fazer #include <functional>. Exemplo:

-
// captureless lambda
-int(*fquad1)(int) = [](int p) -> int { return p*p; };
-std::function<int(int)> fquad2 = [](int p) { return p*p; };
-// capturando variável x (por cópia)
-int x = 10;
-int y = 20;
-// closure x1 (retorna x + 1)
-std::function<int()> x1 = [x]() { return x+1; };
-// capturando todas variáveis locais com =, y por referência
-std::function<int()> fxy = [=, &y]() { y++; return x+y; };
-int z = fxy(); // z==31  y==21
+
// captureless lambda
+int(*fquad1)(int) = [](int p) -> int { return p*p; };
+std::function<int(int)> fquad2 = [](int p) { return p*p; };
+// capturando variável x (por cópia)
+int x = 10;
+int y = 20;
+// closure x1 (retorna x + 1)
+std::function<int()> x1 = [x]() { return x+1; };
+// capturando todas variáveis locais com =, y por referência
+std::function<int()> fxy = [=, &y]() { y++; return x+y; };
+int z = fxy(); // z==31  y==21
@@ -1342,16 +1360,16 @@

Proposta para um std::scan

busca criar uma função scn::scan que substitua a scanf (pelo mesmo raciocínio empregado na abolição do printf). Exemplo:

-
#include <scn/scn.h>
-// lembre-se de incluir o pacote eliaskosunen/scnlib no CMake
-using scn::scan;
-// ...
-int x = 0;
-int y = 0;
-auto resto = scan("10 20", "{}", x);
-scan(resto, "{}", y);
-print("x={} y={}", x, y);
-// x=10 y=20
+
#include <scn/scn.h>
+// lembre-se de incluir o pacote eliaskosunen/scnlib no CMake
+using scn::scan;
+// ...
+int x = 0;
+int y = 0;
+auto resto = scan("10 20", "{}", x);
+scan(resto, "{}", y);
+print("x={} y={}", x, y);
+// x=10 y=20

Ponteiro cycles::relation_ptr

@@ -1362,15 +1380,15 @@

Ponteiro cycles::relation_ptr

em um C++ futuro. Exemplo:

Para utilizar, basta fazer #include <cycles/relation_ptr>. Exemplo:

-
using cycles::relation_pool;
-using cycles::relation_ptr;
-// veja instruções em: https://github.com/igormcoelho/cycles
-relation_pool<> grupo;
-auto r1 = grupo.make<int>(10);
-auto r2 = std::move(r1);
-print("*r2={}\n",*r2);
-// *r2=10
-r2.reset(); // apaga ponteiro r2 manualmente
+
using cycles::relation_pool;
+using cycles::relation_ptr;
+// veja instruções em: https://github.com/igormcoelho/cycles
+relation_pool<> grupo;
+auto r1 = grupo.make<int>(10);
+auto r2 = std::move(r1);
+print("*r2={}\n",*r2);
+// *r2=10
+r2.reset(); // apaga ponteiro r2 manualmente
@@ -1457,15 +1475,15 @@

Modularização Básica

Um programa começa pelo seu “ponto de entrada” (ou entrypoint), tipicamente uma função int main():

-
#include<iostream> // inclui arquivo externo
-int main() {
-   return 0;       // 0 significa: nenhum erro
-}
-

A declaração de funções pode ser feita antes da definição:

-
int quadrado(int p); // declara a função 'quadrado'
-int quadrado(int p) {
-   return p*p;       // implementa a função 'quadrado'
+
#include<iostream> // inclui arquivo externo
+int main() {
+   return 0;       // 0 significa: nenhum erro
 }
+

A declaração de funções pode ser feita antes da definição:

+
int quadrado(int p); // declara a função 'quadrado'
+int quadrado(int p) {
+   return p*p;       // implementa a função 'quadrado'
+}

Declarações vem em arquivos .h, enquanto as respectivas implementações em arquivo .cpp (ou juntas como .hpp).

@@ -1517,49 +1535,49 @@

Tipos na biblioteca padrão C++

vantajoso usar o existente na STL, chamado std::pair (o prefixo std:: é chamado namespace e evita colisões de nomes):

-
#include<iostream> // funções de entrada/saída
-#include<tuple>    // agregados de par e tupla
-int main() {
-   std::pair<int, char> p {5, 'C'}; // direct init.
-   printf("%d %c\n", p.first, p.second); // 5 C
-   // ...
-}
+
#include<iostream> // funções de entrada/saída
+#include<tuple>    // agregados de par e tupla
+int main() {
+   std::pair<int, char> p {5, 'C'}; // direct init.
+   printf("%d %c\n", p.first, p.second); // 5 C
+   // ...
+}

Relembrando (agregado Z)

-
// Em C++ (tipo agregado Z)
-class Z
-{
-public:
-   int x;
-   // imprime campo x
-   void imprimex() {
-      printf("%d\n", this->x);
-   }
-};
+
// Em C++ (tipo agregado Z)
+class Z
+{
+public:
+   int x;
+   // imprime campo x
+   void imprimex() {
+      printf("%d\n", this->x);
+   }
+};

Relembrando (conceito TemImprimeX)

-
template<typename Agregado>
-concept bool
-TemImprimeX = requires(Agregado a) {
-   {
-      a.imprimex()
-   }
-};
+
template<typename Agregado>
+concept bool
+TemImprimeX = requires(Agregado a) {
+   {
+      a.imprimex()
+   }
+};

Verificações com assert

Durante o desenvolvimento, é útil verificar partes do código com testes simples e necessários para a corretude do mesmo (em tempo real). Para isso, podemos utilizar o assert(). Exemplo:

-
int x = 10;
-x++;
-assert(x == 11); // x deveria ser 11
+
int x = 10;
+x++;
+assert(x == 11); // x deveria ser 11

Da mesma forma, podemos verificar tipos, especialmente conceitos, em tempo de compilação:

-
// verifica se tipo agregado Z tem método imprimex()
-static_assert(TemImprimeX<Z>); 
+
// verifica se tipo agregado Z tem método imprimex()
+static_assert(TemImprimeX<Z>); 

Testes com a biblioteca Catch2

@@ -1568,17 +1586,17 @@

Testes com a biblioteca Catch2

biblioteca Catch2.

Basta criar um arquivo de teste, por exemplo, teste.cpp:

-
#include "resto.hpp"
-
-#define CATCH_CONFIG_MAIN // catch2 main()
-#include "catch.hpp"
-
-TEST_CASE("Testa inicializacao do agregado Z") 
-{
-   auto z1 = Z{.x = 10};
-   // verifica se, de fato, z1.x vale 10
-   REQUIRE(z1.x == 10);
-}
+
#include "resto.hpp"
+
+#define CATCH_CONFIG_MAIN // catch2 main()
+#include "catch.hpp"
+
+TEST_CASE("Testa inicializacao do agregado Z") 
+{
+   auto z1 = Z{.x = 10};
+   // verifica se, de fato, z1.x vale 10
+   REQUIRE(z1.x == 10);
+}

Baixando o Catch2 e executando

diff --git a/slides/1-revisao-tipos/makefile b/slides/1-revisao-tipos/makefile index 12ec239..a7de399 100644 --- a/slides/1-revisao-tipos/makefile +++ b/slides/1-revisao-tipos/makefile @@ -9,9 +9,10 @@ all: deps # # # -F pandoc-crossref - /usr/bin/pandoc --toc -s --embed-resources --standalone -V theme:Warsaw -t beamer \ + /usr/bin/pandoc --toc -s --embed-resources --standalone --filter pandoc-latex-fontsize -V theme:Warsaw -t beamer \ -H header.tex \ $(MDFILE) -o $(OUTPDF) --slide-level 2 +# $(OUTPDF) #--filter pandoc-source-exec