-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathConcetti_Avanzati.tex
1774 lines (1300 loc) · 61 KB
/
Concetti_Avanzati.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
% ----------------------------- CONCETTI AVANZATI ------------------------------------
\chapter{Concetti Avanzati}
% Argomenti di questo capitolo da trattare:
%TODO: Signal Handling? (magari in un capitolo sul multithreading)
%TODO: Writing C++ code efficiently in Competitive Programming? (magari in un capitolo apposito)
%TODO: Dependency Injection
%TODO: std::bad_alloc (Insomma, non necessaria per sto capitolo credo)
%TODO: magari aggiungere nel capitolo "basi del linguaggio": struct destructors che servono se allochi della memoria nelle struct, non se le usi, ma se allochi.
%TODO: xvalue? (oppure lo aggiungo quando parlo di lvalue e rvalue)
%TODO: performance optimization, performance, optimization techniques?
%TODO: un esempio è usare ++i al posto di i++
%TODO: esempi: Premature Pessimization to avoid Premature Optimization.
%TODO: template metaprogramming? (nel capitolo dei Design Patterns)
% -------------------------- SECTION: INTRODUZIONE -----------------------------------
\section{Introduzione}
\textsf{\small In questo capitolo "finale" tratterò argomenti un po' più complessi o che almeno non mi verrebbe da mettere negli altri due capitoli precedenti.} \\
\textsf{\small Verranno trattati argomenti come gli smart pointers e quindi unique pointers, share pointers, weak pointers, le friend function e altri importanti concetti avanzati.} \\
% -------------------------- SECTION: FRIEND KEYWORD ---------------------------------
\newpage
\section{Friend Keyword}
\subsection{Friend Class}
\textsf{\small \textbf{Definizione: } La keyword \textbf{friend} è usata per accedere ai membri privati e protetti di una classe nella quale è dichiarata \textbf{friend}.} \\
\begin{lstlisting}
#include <iostream>
class A {
public:
A() { a = 0 };
friend class B; // Classe amica.
private:
int a;
};
class B {
public:
void showA(A& x)
{
// Visto che B è un'amica di A, può accedere ai membri privati di A.
std::cout << "A::a : " << x.a;
}
};
int main()
{
A a;
B b;
b.showA(); //Output: A::a : 0
return 0;
}
\end{lstlisting}
\subsection{Friend Function}
\textsf{\small \textbf{Definizione: } Come per le \textbf{classi friend}, una \textbf{funzione friend} ha accesso speciale ai membri privati e protetti.} \\
\textsf{\small Una \textbf{friend function} può essere: } \\
\begin{itemize}
\item \textsf{\small Un membro di un'altra classe.}
\item \textsf{\small Una funzione globale.}
\end{itemize}
\textsf{\small Alcuni importanti punti riguardo alle \textbf{friend} functions e classes: } \\
\begin{itemize}
\item \textsf{\small Dovrebbero essere usate solo in maniera limitata. Troppe funzioni o classi \textbf{friend} diminuiscono l'encapsulazione.}
\item \textsf{\small L'amicizia non è reciproca. Se la classe A è amica della classe B, allora B non è automaticamente amica di A.}
\item \textsf{\small L'amicizia non è ereditata.}
%\item \textsf{\small }
\end{itemize}
\begin{lstlisting}
#include <iostream>
class A {
public:
friend void printWidth( A a);
void setWidth(double w);
private:
double width;
};
// Definizione della funzione membro di A.
void A::setWidth(double w)
{
width = w;
}
// printWidth non è una funzione membro di nessuna classe.
void printWidth( A a )
{
// Visto che la funzione printWidth è amica di A, può accedere direttamente a qualsiasi membro di A.
std::cout << "Width di A: " << a.width << std::endl;
}
int main()
{
A a;
a.setWidth(11.1);
// Uso la funzione amica per stampare la width di a.
printWidth( a ) ; //Output: Width di A: 11.1
return 0;
}
\end{lstlisting}
% -------------------------- SECTION: SMART POINTERS ---------------------------------
\newpage
\section{Smart Pointers}
\textsf{\small \textbf{Definizione: } Gli \textbf{smart pointers} (puntatori intelligenti) sono dei puntatori che, in più rispetto ai normali puntatori, sono in grado di deallocare la memoria automaticamente, senza che il programmatore debba occuparsene ed evitando \emph{memory leak}.} \\
\subsection{Differenze con i puntatori normali}
\textsf{\small I \textbf{puntatori} servono per poter accedere a delle risorse che sono esterne al programma (alla memoria heap). Grazie ai puntatori saremo in grado di modificare direttamente la risorsa esterna, al posto di doverne fare una copia.} \\
\textsf{\small Il problema di questi puntatori è che se non deallocati correttamente potrebbero portare ad uno spreco della memoria heap, il che è un \emph{memory leak}.} \\
\begin{lstlisting}
#include <iostream>
class Rectangle {
private:
int width;
int height;
};
void fun()
{
Rectangle* p = new Rectangle();
}
int main()
{
while(1)
{
fun();
}
//Output: Il problema è che quando la funzione fun termina, il puntatore p verrà distrutto come fosse una variabile locale, ma la memoria allocata non verrà deallocata, perché ci siamo scordati di usare \emph{delete p}; alla fine della funzione.
// Ciò è un problema perché verrà sempre allocata altra memoria e mai deallocata, occupando spazio, sprecando memoria, il che è un \emph{memory leak}.
// L'intera memoria heap potrebbe diventare inutile per questo motivo.
return 0;
}
\end{lstlisting}
\textsf{\small Il problema è che quando la funzione fun termina, il puntatore p verrà distrutto come fosse una variabile locale, ma la memoria allocata non verrà deallocata, perché ci siamo scordati di usare \emph{delete p}; alla fine della funzione.} \\
\textsf{\small Ciò è un problema perché verrà sempre allocata altra memoria e mai deallocata, occupando spazio, sprecando memoria, il che è un \emph{memory leak}.} \\
\textsf{\small L'intera memoria heap potrebbe diventare inutile per questo motivo. } \break
\textsf{\small Uno \textbf{smart pointer} è un \emph{wrapper} (un wrapper è un'entità che ne encapsula un'altra; è del codice che letteralmente avvolge, incarta, impacchetta, confeziona dell'altro codice) su un puntatore con un'operatore \textbf{*} e \textbf{->} overloaded.} \\
\textsf{\small La memoria allocata dinamicamente verrebbe così automaticamente liberata.} \\
\begin{lstlisting}
// Una generica classe Smart Pointer
#include <iostream>
template <class T>
class SmartPointer {
T *ptr;
public:
SmartPointer(T *ptr = NULL)
{
p = ptr;
}
~SmartPointer()
{
delete ptr;
}
T & operator * ()
{
return *ptr;
}
T * operator ->()
{
return ptr;
}
};
int main()
{
SmartPointer<int> p(new int());
*p = 22;
std::cout << "Valore di *p: " << *p << std::endl; //Output: Valore di *p: 22
return 0;
}
\end{lstlisting}
%TODO: dynamic_pointer_cast
%TODO: const_pointer_cast
\subsection{unique pointers}
\textsf{\small \textbf{Definizione: } Gli \textbf{unique pointers} sono un tipo di \textbf{smart pointers} che memorizzano un solo puntatore alla volta.} \\
\textsf{\small Prima degli \textbf{unique\_ptr} c'erano gli \textbf{auto\_ptr} (C++98), ma dal C++11 sono \emph{deprecati} (ovvero che non è raccomandato utilizzare, è obsoleto o ha bisogno di ulteriore sviluppo), quindi ora si consiglia di utilizzare gli \textbf{unique\_ptr}. } \\
\textsf{\small Sarà necessario includere \textbf{<memory>} per poter usufruire degli \textbf{unique pointers}.} \\
\begin{lstlisting}
#include <iostream>
#include <memory> // Per gli unique pointers, ecc.
// Per dichiarare un unique pointer
std::unique_ptr<int> p(new int(3));
\end{lstlisting}
\newpage %TODO: questo \newpage mi serviva per evitare gli spazi bianchi sopra alla subsection unique pointers
\begin{figure}[H]
\centering
\includegraphics[width=1\textwidth, height=1\textheight, keepaspectratio]{./imgs/unique_ptr_definition.png}
\caption{Unique ptr}
\label{fig:unique_ptr_definition}
\end{figure}
\textsf{\small Se lo \textbf{unique\_ptr} viene distrutto, anche la memoria allocata nell'heap viene distrutta di conseguenza.} \\
\begin{figure}[H]
\centering
\includegraphics[width=1\textwidth, height=1\textheight, keepaspectratio]{./imgs/unique_ptr_delete.png}
\caption{Unique ptr delete}
\label{fig:unique_ptr_delete}
\end{figure}
\textsf{\small Per creare uno \textbf{unique\_ptr} si può anche utilizzare \textbf{std::make\_unique}.} \\
\begin{lstlisting}
#include <iostream>
class Rectangle {
public:
Rectangle(int w, int h)
{
this->width = w;
this->height = h;
}
int area()
{
return width * height;
}
private:
int width;
int height;
};
int main()
{
auto pRect = std::make_unique<Rectangle>(3, 4);
std::cout << "Area del rettangolo: " << pRect->area() << std::endl; //Output: Area del rettangolo: 12
return 0;
}
\end{lstlisting}
\subsubsection{Differenza tra std::make\_unique vs std::unique\_ptr}
\textsf{\small Ci sono varie ragioni per cui utilizzare \textbf{std::make\_unique} al posto di \textbf{std::unique\_ptr} con la new: } \\
\begin{itemize}
\item \textsf{\small È sicuro nel caso si vogliano creare dei temporanei, mentre con la new ti devi ricordare la regola: del non usare temporanei senza nome. }
\item \textsf{\small Con l'utilizzo di \textbf{make\_unique} si può finalmente evitare di usare la \textbf{new}, a differenza della vecchia regola: mai usare la \textbf{new} tranne per gli \textbf{unique\_ptr}.}
\item \textsf{\small Non richiede \emph{type usage} ridondante: \emph{unique\_ptr<T>(new T())} -> make\_unique<T>().} \\
\item \textsf{\small Così da non dover esplicitare gli argomenti dei \emph{template types}.}
\item \textsf{\small Aggiunge sicurezza riguardo le eccezioni.}
\item \textsf{\small Altrimenti non potresti accedere al costruttore della classe fuori dallo \emph{scope} corrente.}
%\item \textsf{\small }
\end{itemize}
\subsubsection{Ownership | move}
\textsf{\small Un \textbf{unique pointer} è una relazione 1 a 1 con l'oggetto allocato.} \\
\textsf{\small Non può essere copiato o passato per valore, però la \textbf{ownership} (proprietà) dell'oggetto può essere trasferita.} \\
\begin{lstlisting}
#include <iostream>
class Person {
public:
Person(std::string s) : name(s) {};
~Person() { std::cout << "Libero spazio" << std::endl };
std::string getName() { return this->name };
private:
std::string name;
};
int main()
{
auto ptrPerson = std::make_unique<Person>("Luigi");
std::cout << "Nome: " << ptrPerson->getName() << std::endl; //Output: Nome: Luigi
std::unique_ptr<Person> ptrPerson2;
ptrPerson2 = std::move(ptrPerson);
std::cout << "Nome: " << ptrPerson2->getName() << std::endl; //Output: Nome: Luigi
std::cout << "Nome dopo il trasferimento dell'ownership: " << ptrPerson->getName() << std::endl; //Output: [non stampa niente]
return 0;
}
\end{lstlisting}
\begin{figure}[H]
\centering
\includegraphics[width=1\textwidth, height=1\textheight, keepaspectratio]{./imgs/unique_ptr_move2.png}
\caption{Unique ptr move}
\label{fig:unique_ptr_move2}
\end{figure}
\subsubsection{Operazioni sugli unique\_ptr}
\textsf{\small Varie operazioni sono supportate sugli \textbf{unique\_ptr}: } \\
\begin{itemize}
\item \textsf{\small \textbf{*} : Dereferenza del puntatore.}
\item \textsf{\small \textbf{->} : Accedere ai membri della classe.}
\item \textsf{\small \textbf{.get()} : per ottenere il \emph{raw pointer} del \textbf{unique\_ptr} (non cancellarlo, perché è gestito dal unique pointer; è da usare solo per calcoli).}
\item \textsf{\small \textbf{.reset(new int())} : cancella il vecchio oggetto e ne crea uno nuovo (al posto di new int() avremmo potuto passare qualsiasi altro oggetto, era per fare un esempio).}
\item \textsf{\small \textbf{move} : trasferisce la proprietà del \textbf{unique\_ptr}.}
\item \textsf{\small \textbf{swap} : per scambiare due \textbf{unique pointers}.}
\item \textsf{\small \textbf{if(unique\_ptr)} : se passiamo uno \textbf{unique\_ptr} all'if, questo restituisce falso se non è associato a nessun oggetto.}
%\item \textsf{\small \textbf{} : }
\end{itemize}
\subsubsection{Passare uno unique\_ptr ad una funzione}
\textsf{\small Utilizziamo \textbf{std::move} per trasferire la proprietà del \textbf{unique\_ptr}.} \\
\begin{lstlisting}
#include <iostream>
#include<memory>
struct A {
int x;
~A() { std::cout << "Libero spazio" << std::endl };
};
void passUniquePtr(std::unique_ptr<A> a)
{
// Usciti dalla funzione, lo unique\_ptr e il suo oggetto vengono cancellati, perché locali alla funzione.
std::cout << "Puntatore ricevuto" << '\n';
a->x = 5;
std::cout << "a.x: " << a->x << std::endl;
}
int main()
{
auto ptrA = std::make_unique<A>();
passUniquePtr(std::move(ptrA));
// true = ptrA è vuoto.
if(!ptrA)
{
std::cout << "ptrA è vuoto" << std::endl;
}
//Output: Puntatore ricevuto
//Output: a.x: 5
//Output: Libero spazio
//Output: ptrA è vuoto
return 0;
}
\end{lstlisting}
\subsubsection{Restituire un unique\_ptr}
\textsf{\small Si può restituire uno \textbf{unique\_ptr} da una funzione. } \\
\begin{lstlisting}
#include <iostream>
#include <memory>
class A {};
std::unique_ptr<A> returnUniquePtr()
{
auto a = std::make_unique<A>();
return a;
}
int main()
{
auto ptrA = returnUniquePtr();
if(ptrA)
{
std::cout << "ptrA ha un oggetto. " << std::endl;
}
//Output: ptrA ha un oggetto.
return 0;
}
\end{lstlisting}
\subsubsection{Membri delle classi: unique pointer vs raw pointer vs reference}
\textsf{\small } \\
\begin{itemize}
\item \textsf{\small \textbf{Unique pointer membro della classe} : la classe è la proprietaria dell'oggetto del puntatore.}
\item \textsf{\small \textbf{Raw pointer membro della classe} : La classe è un osservatore e non è responsabile di rimuovere l'oggetto puntato dal puntatore. Viene rimosso da uno smart pointer fuori dalla classe.}
\item \textsf{\small \textbf{Referenza membro della classe} : è garantito che la referenza contiene dati validi mentre la classe è "viva".}
%\item \textsf{\small }
\end{itemize}
\subsection{share pointers}
\textsf{\small \textbf{Definizione: } Gli \textbf{shared pointers} sono un tipo di \textbf{smart pointers} dove più di un puntatore può puntare allo stesso oggetto e un contatore (\emph{Reference Counter}) verrà mantenuto di conseguenza.} \\
\textsf{\small Abbiamo sempre bisogno di includere l'header \textbf{<memory>} per poterlo utilizzare.} \break
\begin{lstlisting}
#include <iostream>
#include <memory>
class A {
public:
int x;
A(int x) : x(x){};
};
int main()
{
auto sharedPtr1 = std::make_shared<A>(7); // oppure si può anche fare: std::shared\_ptr<A> sharedPtr1(new A{7});
std::shared_ptr<A> sharedPtr2 = sharedPtr1;
std::shared_ptr<A> sharedPtr3 = sharedPtr1;
// Tutti e tre gli \textbf{shared1\_ptr} puntano allo stesso oggetto.
return 0;
}
\end{lstlisting}
\newpage %TODO: questo \newpage mi serviva per evitare gli spazi bianchi sopra la subsection share pointers.
\begin{figure}[H]
\centering
\includegraphics[width=1\textwidth, height=1\textheight, keepaspectratio]{./imgs/shared_ptr3.png}
\caption{Shared ptr}
\label{fig:shared_ptr3}
\end{figure}
\textsf{\small Possiamo creare uno \textbf{shared pointer} sia con \textbf{shared\_ptr} sia con \textbf{make\_shared}.} \\
\subsubsection{Differenza tra std::shared\_ptr vs std::make\_shared}
\textsf{\small Una delle differenze tra questi due è che \textbf{make\_shared} performa una sola allocazione nell'heap, mentre \textbf{shared\_ptr} ne fa due.} \\
\textsf{\small \textbf{shared\_ptr} si occupa di due entità: } \\
\begin{itemize}
\item \textsf{\small Il blocco di controllo (\emph{control block}) che memorizza dei metadati come \emph{ref-counts} (contatore delle referenze all'oggetto), \emph{type-erased deleter}, ecc.}
\item \textsf{\small l'oggetto stesso.}
\end{itemize}
\textsf{\small \textbf{std::make\_shared} fa una singola allocazione nell'heap per lo spazio necessario sia per il \emph{control block} sia per \emph{l'oggetto}. } \break
\textsf{\small Inoltre \textbf{std::make\_shared} è \emph{exception-safe} (sicuro per quanto riguarda le eccezioni).} \\
\textsf{\small Per di più, \textbf{make\_shared} sfrutta dell'ottimizzazione conosciuta come \emph{We know Where You Live} che permette al \emph{control block} di essere un piccolo puntatore, quindi \textbf{make\_shared} non solo evita un'ulteriore allocazione, ma alloca anche meno memoria totale.} \break
\textsf{\small Un problema che potrebbe esserci per quanto riguarda \textbf{std::make\_shared} è che visto che fa una singola allocazione, non c'è modo di deallocare la memoria del \emph{control block} e dell'\emph{oggetto} in modo indipendente. Un altro svantaggio, di conseguenza è che essendoci una singola allocazione, la memoria non può essere deallocata finché il \emph{control block} non è più usato. } \\
\subsubsection{Operazioni sui shared pointers}
\textsf{\small Sono possibili varie operazioni sugli \textbf{shared pointers}: } \\
\begin{itemize}
\item \textsf{\small \textbf{(*nomepuntatore).variabile} : dereferenza}
\item \textsf{\small \textbf{nomepuntatore->variabile} : dereferenza come sopra}
\item \textsf{\small \textbf{.get()} : per poter accedere al \emph{raw pointer} chiamato \textbf{stored pointer}.}
\item \textsf{\small \textbf{use\_count()} : per ottenere il numero di \textbf{shared\_ptr} che puntano allo stesso oggetto.}
\item \textsf{\small \textbf{.reset()} : scollega e svuota il puntatore.}
\end{itemize}
\textsf{\small Lo \textbf{shared pointer} inoltre allo \emph{stored pointer}, possiede un secondo puntatore che punta ad un \textbf{control block}. Il \emph{control block} ha un \emph{reference counter} (contatore delle referenze) che memorizza il numero di \textbf{shared pointers} che puntano allo stesso oggetto.} \\
\newpage %TODO: questo mi serviva per evitare gli spazi nell'itemize della subsubsection "Operazioni sui shared pointers".
\begin{figure}[H]
\centering
\includegraphics[width=1\textwidth, height=1\textheight, keepaspectratio]{./imgs/shared_ptr_structure.png}
\caption{Shared ptr structure}
\label{fig:shared_ptr_structure}
\end{figure}
\subsubsection{Distruzione degli shared pointers}
\textsf{\small Quando verrà eliminato l'oggetto gestito dagli \textbf{shared\_ptr}?} \\
\textsf{\small Quando uno \textbf{shared pointer} viene distrutto, allora il \emph{control block} decrementerà il \emph{reference counter}.} \\
\textsf{\small L'oggetto verrà eliminato quando l'ultimo \textbf{shared\_ptr} verrà eliminato. (e quindi quando il \emph{reference counter} arriverà a 0. )} \\
\begin{lstlisting}
#include <iostream>
#include <memory>
class A {
public:
int x;
A(int x) : x(x) {};
};
int main()
{
auto shrPtr1 = std::make_shared<A>(5);
auto shrPtr2 = shrPtr1;
auto shrPtr3 = shrPtr1;
{
auto shrPtr4 = shrPtr1;
std::cout << shrPtr1.use_count() << std::endl; //Output: 4
}
std::cout << shrPtr1.use_count() << std::endl; //Output: 3
shrPtr3 = std::make_shared<A>(8); // shrPtr3 punta ad un altro oggetto.x
shrPtr2.reset(); // shrPtr2 scollegato e svuotato.
std::cout << shrPtr1.use_count() << std::endl; //Output: 1
return 0;
}
\end{lstlisting}
\begin{figure}[H]
\centering
\includegraphics[width=1\textwidth, height=1\textheight, keepaspectratio]{./imgs/shared_ptr_destruction.png}
\caption{Shared ptr destruction}
\label{fig:shared_ptr_destruction}
\end{figure}
\subsubsection{Passare gli shared pointers ad una funzione}
\textsf{\small Se una funzione vuole l'\emph{ownership} (proprietà) su un \textbf{shared\_ptr}, possiamo passarlo per valore: } \\
\begin{lstlisting}
#include <iostream>
#include <memory>
void function(std::shared_ptr<int> sp)
{
std::cout << sp.use_count() << std::endl;
}
int main()
{
auto sp1 = std::make_shared<int>(6);
std::cout << sp1.use_count() << std::endl; //Output: 1
function(sp1); //Output: 2
std::cout << sp1.use_count() << std::endl; //Output: 1 (lo shared\_ptr nella funzione "function" viene distrutto una volta usciti da essa, perché è locale alla funzione)
return 0;
}
\end{lstlisting}
\subsubsection{Restituire gli shared pointers}
\textsf{\small Una funzione può restituire \textbf{shared\_ptr} per valore: } \\
\begin{lstlisting}
#include <iostream>
#include <memory>
std::shared_ptr<int> function()
{
auto sp = std::make_shared<int>(9);
return sp;
}
int main()
{
auto sp1 = function(); // Lo shared\_ptr dentro alla funzione non esiste più, però viene ritornato e recuperato nella variabile sp1.
std::cout << sp1.use_count() << std::endl; //Output: 1
std::cout << *sp1 << std::endl; //Output: 9
return 0;
}
\end{lstlisting}
\textsf{\small Un problema col restituire uno \textbf{shared\_ptr}: se lo devi restituire al "mondo esterno", meglio restituirlo come \emph{reference}, perché altrimenti uno potrebbe chiamare la \textbf{.reset()} su quello \textbf{shared pointer}.} \break %TODO: ma non potrebbero comunque chiamarla la .reset() anche con la reference?
\textsf{\small Un altro modo per restituire uno \textbf{shared\_ptr} è attraverso \emph{std::allocate\_shared}.} \\
\begin{lstlisting}
#include <iostream>
#include <memory>
int main () {
std::allocator<int> alloc; // allocatore di default per gli int.
std::default_delete<int> del; // deleter di default per gli int.
std::shared_ptr<int> foo = std::allocate_shared<int> (alloc,12);
auto bar = std::allocate_shared<int> (alloc,24);
auto baz = std::allocate_shared<std::pair<int,int>> (alloc,33,44);
std::cout << "*foo: " << *foo << '\n'; //Output: *foo: 12
std::cout << "*bar: " << *bar << '\n'; //Output: *bar: 24
std::cout << "*baz: " << baz->first << ' ' << baz->second << '\n'; //Output: *baz: 33 44
return 0;
}
\end{lstlisting}
\subsubsection{static\_pointer\_cast}
\textsf{\small \textbf{Definizione: } \textbf{static\_pointer\_cast} è una funzione, non una keyword e restituisce uno \textbf{shared\_ptr} che possiede e contiene un puntatore all'oggetto costruito.} \\
\textsf{\small Se il parametro passato non è vuoto, ciò che viene restituito condivide la proprietà con il parametro passato, quindi il contatore viene incrementato di 1.} \\
\textsf{\small Se il parametro è vuoto (non possiede nulla), allora l'oggetto ritornato è uno \textbf{shared\_ptr} vuoto.} \\
\begin{lstlisting}
#include <iostream>
#include <memory>
class Base {};
class Derived : public Base {
public:
void print()
{
std::cout << "Hello World!" << std::endl;
}
};
int main()
{
std::shared_ptr<Base> spBase(std::make_shared<Derived>());
std::static_pointer_cast<Derived>(spBase)->print();
static_cast<Derived*>(spBase.get())->print();
//Output: Hello World!
//Output: Hello World!
return 0;
}
\end{lstlisting}
\begin{figure}[H]
\centering
\includegraphics[width=1\textwidth, height=1\textheight, keepaspectratio]{./imgs/std_shared_ptr_std_static_pointer_cast2.png}
\caption{Static pointer cast}
\label{fig:std_shared_ptr_std_static_pointer_cast2}
\end{figure}
%TODO: dynamic_pointer_cast (volendo, ma non necessario, giusto per approfondimento)
%TODO: const_pointer_cast
\subsubsection{enable\_shared\_from\_this}
\textsf{\small \textbf{Definizione: } \textbf{std::enable\_shared\_from\_this} permette a un oggetto \emph{t} che è gestito da uno \textbf{shared\_ptr} \emph{sp} di generare, in modo sicuro, degli \textbf{shared\_ptr} addizionali, istanze \emph{sp1}, \emph{sp2} che condividono tutti la proprietà dell'oggetto \emph{t} con \emph{sp}.} \break
\textsf{\small Ereditare da \textbf{std::enable\_shared\_from\_this} fornisce il tipo T con una funzione membro \emph{shared\_from\_this()}. Se un oggetto \emph{t} di tipo T è gestito da uno \textbf{shared\_ptr} \emph{sp}, allora chiamare \emph{shared\_from\_this()} restituirà un nuovo \textbf{shared\_ptr} che condivide la proprietà di \emph{t} con \emph{sp}. } \\
\begin{lstlisting}
#include <iostream>
#include <memory>
struct B : std::enable_shared_from_this<B> {};
int main()
{
std::shared_ptr<B> foo, bar;
foo = std::make_shared<B>();
bar = foo->shared_from_this();
if(!foo.owner_before(bar) && !bar.owner_before(foo))
{
std::cout << "foo e bar condividono la proprietà" << std::endl;
}
//Output: foo e bar condividono la proprietà
return 0;
}
\end{lstlisting}
\textsf{\small Inoltre, c'è anche una funzione \emph{weak\_from\_this} che restituisce un \textbf{weak\_ptr} che tiene traccia della proprietà di \textbf{*this} da parte di tutte le istanze di \textbf{shared\_ptr}.} \\
\subsubsection{Performance degli shared pointers}
\textsf{\small Uno \textbf{shared pointer} ha bisogno di due \emph{raw pointers}. Un insieme di \textbf{shared pointers} hanno bisogno di essere gestiti da una \emph{control unit} (\emph{control block}). Quindi la memoria che uno \textbf{shared pointer} occupa è maggiore dei \emph{raw} e degli \textbf{unique} pointers.} \\
\subsubsection{Shared pointers, unique pointers or raw pointers}
\textsf{\small Se un oggetto ha bisogno di un singolo proprietario per tutta la durata del programma e possiamo immaginare il puntatore come un'entità singola, allora usiamo un \textbf{unique pointer}. Per delle performance più buone gli \textbf{unique pointers} sono migliori rispetto agli \textbf{shared pointers}.} \\
\textsf{\small Gli \textbf{shared pointers} sono utili dove non abbiamo bisogno di pensare alle \emph{performance}, \emph{ownership} e \emph{lifetime} degli oggetti.}
\subsection{weak pointers}
\textsf{\small \textbf{Definizione: } Un \textbf{weak pointer} è un tipo di \textbf{smart pointer} che non prende la proprietà dell'oggetto, ma agisce come un osservatore. Non partecipa al \emph{reference counter} (non viene contato) e non estende la \emph{lifetime} dell'oggetto. } \break
\textsf{\small Sono usati, principalmente, per rompere la dipendenza circolare degli \textbf{shared pointers}.} \\
\subsubsection{Problema della dipendenza ciclica}
\textsf{\small \textbf{Definizione: } Mettiamo di avere due classi: A e B, se entrambe hanno un puntatore che punta all'altra, avremo un ciclo e il \emph{use\_count()} non arriverà mai a 0, il che creerebbe un problema nella rimozione di questi due puntatori.} \\
\begin{figure}[H]
\centering
\includegraphics[width=1\textwidth, height=1\textheight, keepaspectratio]{./imgs/shared_ptr_problem_cyclic_dependency.jpg}
\caption{Cyclic dependency}
\label{fig:shared_ptr_problem_cyclic_dependency}
\end{figure}
\textsf{\small Per questo motivo usiamo gli \textbf{weak pointers}, perché non vengono conteggiati nel \emph{reference counter}. Possono, comunque avere accesso all'oggetto.} \\
\begin{figure}[H]
\centering
\includegraphics[width=1\textwidth, height=1\textheight, keepaspectratio]{./imgs/shared_ptr_problem_cyclic_dependency2.jpg}
\caption{Cyclic dependency}
\label{fig:shared_ptr_problem_cyclic_dependency2}
\end{figure}
\textsf{\small Quindi, il problema della \emph{dipendenza ciclica} si risolve con l'utilizzo degli \textbf{weak pointers}.} \\
\subsubsection{Quando usare i weak pointers?}
\textsf{\small \textbf{Quando usare i weak pointers?}} \break
\textsf{\small Quando vuoi riferire al tuo oggetto da molteplici posti, per quelle referenze dove non è okay ignorarle e deallocarle.} \\
%TODO: risolvere problema del danglin pointer
\subsubsection{Operazioni sugli weak pointers}
\textsf{\small Ci sono varie operazioni sui \textbf{weak pointers}: } \\
\begin{itemize}
\item \textsf{\small \textbf{*} : dereferenza}
\item \textsf{\small \textbf{->} : dereferenza, accedere ai membri della classe/struct, ecc.}
\item \textsf{\small \textbf{.lock()} : restituisce uno \textbf{shared\_ptr} con le informazioni preservate nel \textbf{weak\_ptr} se non è \emph{expired}. Se il \textbf{weak\_ptr} è \emph{expired} (scaduto), la funzione restituisce un \textbf{shared\_ptr} vuoto.}
%\item \textsf{\small \textbf{.get()} : }
\item \textsf{\small \textbf{.reset()} : cancella il vecchio oggetto e ne crea uno nuovo.}
\item \textsf{\small \textbf{.swap()} : scambia due \textbf{weak pointers}.}
\item \textsf{\small \textbf{.use\_count()} : restituisce il numero di \textbf{shared pointers} che puntano allo stesso oggetto.}
\item \textsf{\small \textbf{.expired()} : restituisce se il \textbf{weak\_ptr} è vuoto o non ci sono più \textbf{shared\_ptr} nell' \emph{owner group}. I puntatori "scaduti" (\emph{expired}) sono come \textbf{weak pointers} vuoti quando \emph{locked} e non possono quindi essere più usati.}
\item \textsf{\small \textbf{.owner-before()} : restituisce se l'oggetto deve andare prima del parametro. Se l'oggetto appartiene allo stesso \emph{owner group} del parametro, allora restituisce \emph{false}, anche se il valore memorizzato dai puntatori è diverso.}
%\item \textsf{\small \textbf{} : }
\end{itemize}
\begin{lstlisting}
#include <iostream>
#include <memory>
class Person {
public:
std::string name;
Person(std::string name) : name(name){};
};
int main()
{
std::weak_ptr<Person> wp;
auto teacher = std::make_shared<Person>("Giorgio");
wp = teacher;
// Per controllare se l'oggetto è ancora lì o no.
// lock() restituisce un shared\_ptr temporaneo.
if(auto temp = wp.lock())
{
std::cout << temp->name << std::endl;
} else {
std::cout << "L'oggetto non c'è più" << std::endl;
}
return 0;
}
\end{lstlisting}
\newpage %TODO: questo \newpage mi serviva per gli spazi bianchi.
\begin{figure}[H]
\centering
\includegraphics[width=1\textwidth, height=1\textheight, keepaspectratio]{./imgs/weak_ptr1.png}
\caption{Weak pointers}
\label{fig:weak_ptr1}
\end{figure}
\textsf{\small Uno \textbf{shared pointer} ha un \textbf{control block} che conta il numero di \textbf{shared pointers} e di \textbf{weak pointers}. Quando il contatore degli \textbf{shared pointers} arriva a 0, l'oggetto viene eliminato, ma il \emph{control block} resta vivo finché il contatore dei \textbf{weak pointers} non raggiunge 0.} \\
% -------------------------- SECTION: COPY-AND-SWAP IDIOM ----------------------------
\section{Copy-And-Swap Idiom}
\textsf{\small \textbf{Cos'è il \textbf{copy-and-swap idiom} e a cosa serve?}} \break
\textsf{\small Qualsiasi classe che gestisce una risorsa (\emph{un wrapper}, come uno \textbf{smart pointer}) ha bisogno di implementare la \emph{Rule of Three} (destructor, copy constructor, copy assignment). La \emph{copy-and-swap} assiste il \emph{copy assignment} in due cose: evitare la duplicazione di codice e fornisce una forte sicurezza a livello di eccezioni (\emph{exception safety}).} \\
\textsf{\small Concettualmente funziona utilizzando la funzionalità del \emph{copy constructor} di creare una copia locale dei dati, prendere questa copia con una funzione \emph{swap}, scambiando i vecchi dati con quelli nuovi.} \\
\textsf{\small La copia temporanea viene distrutta, portandosi i vecchi dati con essa. Restiamo con una copia dei nuovi dati.} \\
\textsf{\small Per poter far questo quindi avremo bisogno di: } \\
\begin{itemize}
\item \textsf{\small copy-constructor}
\item \textsf{\small destructor}
\item \textsf{\small swap function}
\end{itemize}
\begin{lstlisting}
#include <iostream>
#include <cstring>
class anyArrayClass
{
int size;
int *ptr;
public:
anyArrayClass(int s=0):size(s),
ptr(size ? new int[size]:nullptr) {}
// Copy constructor
anyArrayClass(const anyArrayClass& obj):size(obj.size),
ptr(size ? new int[size]:nullptr)
{
memmove(ptr, obj.ptr, size*sizeof(int));
}
friend void swap(anyArrayClass& obj1, anyArrayClass& obj2)
{
std::swap(obj1.size, obj2.size);
std::swap(obj1.ptr, obj2.ptr);
}
// overloaded assignment operator
// argomento passato per valore. chiama il copy constructor
anyArrayClass& operator=(anyArrayClass obj)
{
// calling friend function
swap(*this, obj);
return *this;
}
~anyArrayClass()
{
delete[] ptr;
}
};
\end{lstlisting}
\textsf{\small I vantaggi sono: } \\
\begin{itemize} %TODO: questo è da riguardare.
\item \textsf{\small Non c'è più bisogno di controlli per l'assegnamento a se stesso visto che il parametro è passato per valore. Inoltre l'allocazione a se stesso è molto rara quindi l'\emph{overhead} della copiatura non dovrebbe essere un problema.}
\item \textsf{\small Ora il \emph{copy constructor} è usato per creare un oggetto temporaneo, lo swapping (scambio) avverrà soltanto se l'oggetto temporaneo è stato creato affatto. Praticamente, quello che stiamo facendo manualmente, il compilatore lo sta facendo per noi.}
\item \textsf{\small Riusabilità del codice: l'operatore \emph{operator=()} non ha molto codice nel suo corpo, anzi stiamo usando il \emph{copy constructor} e la funzione \emph{swap} per fare il lavoro.}
\end{itemize}
%\textsf{\small \textbf{Nota:} Non puoi usare \textbf{std::swap} visto che internamente usa il \emph{copy constructor} e l'\emph{assignment operator}.} \\ %TODO: c'è bisogno di ulteriori verifiche.
% ---------------------- SECTION: TECNICHE PER IL DEBUGGING --------------------------
\newpage
\section{Tecniche per il debugging}
\textsf{\small \textbf{Definizione: } \textbf{Debugging} si riferisce alle tecniche impiegate dai programmatori per cercare di correggere gli errori, i bugs di un programma.} \\
\textsf{\small Una metodologia di base è questa: } \\
\begin{itemize}
\item \textsf{\small Osservare il problema.}
\item \textsf{\small Identificare la natura del problema.}
\item \textsf{\small Identificare la condizione (o condizioni) che innesca il problema.}
\item \textsf{\small Identificare il meccanismo di guasto, fallimento.}
\item \textsf{\small Fixare il problema.}
%\item \textsf{\small }
\end{itemize}
\textsf{\small Per fare questo potrebbe tornare utile: } \\
\begin{itemize}
\item \textsf{\small Commentare il codice.}
\item \textsf{\small Validare il flusso del codice, programma (\emph{code flow}).}
\item \textsf{\small Controllare valori stampandoli a schermo.}
\end{itemize}
%TODO: magari approfondire, puù degli esempi
% ---------------------- SECTION: DEPENDENCY INJECTION -------------------------------
%TODO: pattern? Magari in un capitolo sui Design Patterns
%\newpage
%\section{Dependency Injection}
%\textsf{\small \textbf{Definizione: } } \\
% ---------------------- SECTION: POINTER TO FUNCTION --------------------------------
\newpage
\section{Puntatore a funzione}
\textsf{\small \textbf{Definizione: } I \textbf{puntatori a funzione} o \textbf{function pointers} sono dei puntatori che puntano a delle funzioni.} \\ %TODO: la definizione è da: "grazie al cazzo".
\begin{lstlisting}
#include <iostream>
void fun(int a)
{
std::cout << "Valore di a: " << a << std::endl;
}
int main()
{
// fun\_ptr è un puntatore alla funzione fun() (quella sopra)
void (*fun_ptr)(int) = &fun;
/* La riga sopra è equivalente alle seguenti due sotto:
void (*fun_ptr)(int);
fun_ptr = &fun;
*/
// Chiamando fun() attraverso fun\_ptr
(*fun_ptr)(10);
return 0;
}
\end{lstlisting}
\textsf{\small Si può anche scrivere così: } \\
\begin{lstlisting}
#include <iostream>
void fun(int a)
{
std::cout << "Il valore di a: " << a << std::endl;
}
int main()
{
void (*fun_ptr)(int) = fun; // \& rimosso
fun_ptr(10); // * rimosso
return 0;
}
\end{lstlisting}
\textsf{\small Alcuni fatti riguardo i \textbf{function pointers} dal C: } \\
\begin{itemize}
\item \textsf{\small Questi puntano all'inizio del codice eseguibile.}
\item \textsf{\small A differenza dei normali puntatori, non allochiamo e deallochiamo memoria usando i \textbf{function pointers}.}
\item \textsf{\small Il nome della funzione può anche essere usato per ottenere l'indirizzo della funzione.}
\item \textsf{\small Proprio come i puntatori normali, possiamo avere un array di \textbf{function pointers}.}
\item \textsf{\small Possono essere usati al posto degli switch.}
\item \textsf{\small Come i puntatori normali anche questi possono essere passati come argomenti e restituiti dalle funzioni.}