#include <iostream>
#include <vector>
#include <algorithm>
#include <memory>
#include <functional>
using namespace std;
//--------SMART POINTERS--------//
struct A {
int data;
};
void foo(unique_ptr<A> p) {
cout << p->data << endl;
}
void foo2(shared_ptr<A> p) {
cout << p->data << endl;
}
int main() {
//--------LAMBDAS--------//
// o Return-type: generally evaluated by compiler, except for complex cases e.g. conditional statements. T.ex. "-> double"
// o Parameters: similar to function parameters in every way.
// o Capture-clauses: can capture external variables from enclosing scopes using
// - [&]: capture all external variables by reference.
// - [=]: capture all external variables by value.
// - [a,&b]: capture 'a' by value and 'b' by reference.
vector<int> v = {1, 3, 4, 5, 6, 7, 8, 9};
cout << "vector v:" << endl; //printing v
for (auto x : v) { cout << x << " ";};
cout << endl;
//Print odd numbers in vector v, const iterators
cout << "odd numbers in vector v:" << endl;
for_each(v.cbegin(), v.cend(), [](int x) {
if (x % 2 != 0) {
cout << x << " ";
}
});
cout << endl;
//Multipliying all odd numbers by 2, non-const iterators
for_each(v.begin(), v.end(), [](int &x) { //x as a reference
if (x % 2 != 0) x *= 2;
});
//Adding the size of the vector to all elements.
int size = v.size();
for_each(v.begin(), v.end(), [=](int &x) { //[=] capture 'size' by value, x as a reference
x += size;
});
//Changes data outside the scope of the lambda by capturing with [ & ].
int OUTSIDEDATA = 10;
auto mofify_outsidedata = [&]() { //[&] capture data by reference
OUTSIDEDATA += 5;
};
mofify_outsidedata();
cout << "OUTSIDEDATA: " << OUTSIDEDATA << endl;
//--------SMART POINTERS--------//
// o Unique_ptr: automatically manages allocated resources on heap.
// o Shared_ptr:
// o Weak_ptr:
//Define a unique_ptr to A inside an arbitrary scope and print the data
unique_ptr<A> pa (new A{4});
cout << pa -> data;
//Try calling foo with your unique_ptr. There is a compile error because you are calling by value, trying to copy the pointer.
foo(std::move(pa)); //move ownership of resource from pa to p inside function
// //--------SHARED PTR--------//
shared_ptr<A> sa(new A{5});
cout << sa -> data;
//Call foo2 first normally and then by moving. Run valgrind on both executables. Is there a memory leak?
//NO LEAKS SHOWN BY FSANITIZE FLAG: -fsanitize=address
//foo2(sa); // check with valgrind
foo2(std::move(sa)); // check with valgrind
// //--------WEAK POINTER--------//
// //Constructing a weak pointer as a shared pointer generates a compile error
// weak_ptr<A> wa(new A {5});
// //Construct a weak pointer to the previous shared pointer and try print the data. There will be a compile error.
// weak_ptr<A> wa = sa;
// cout << wa->data;
// //Use the lock member function to print the data field.
// //--------CIRCULAR DEPENDENCIES--------//
// //Given BhasA and AhasB
// struct BhasA;
// struct AhasB {
// AhasB(shared_ptr<BhasA> b) : m_b(b) {
// resource = new int[4];
// };
// shared_ptr<BhasA> m_b;
// int * resource;
// ~AhasB() {delete [] resource;}
// AhasB(const AhasB &) = delete;
// void operator=(const AhasB &) = delete;
// };
// struct BhasA {
// BhasA() {resource = new int[4];};
// shared_ptr<AhasB> m_a;
// int * resource;
// ~BhasA() {delete [] resource;}
// BhasA(const BhasA &) = delete;
// void operator=(const BhasA &) = delete;
// };
// //Declare one instance each of AhasB and BhasA and link them.
// shared_ptr<BhasA> bptr(new BhasA);
// shared_ptr<AhasB> aptr(new AhasB(bptr));
// bptr->m_a=aptr;
// //There is a memory leak when you run valgrind on the code because of the circular dependency. Fix the memory leak by changing one of the shared_ptr members to a weak pointer.
// //--------USING A DELETER--------//
// //Given B
// struct B {
// B() { b = new int[4]; }
// int * b;
// ~B() { delete [] b; }
// B(const B &) = delete;
// void operator= (const B & ) = delete;
// };
// //Unless the compiler detects it, there will a memory leak when declaring a unique_ptr as below. Verify the memory leak with valgrind.
// unique_ptr<B> pb(new B[2]);
// //The memory leak is because the unique_ptr assumes it points to a single object not to an array.
// //In order to fix the memory leak you need to create a function that does a correct deletion of the objects.
// //Write a lambda function that does a correct deletion of the array
// auto deleter = // YOUR LAMBDA HERE
// unique_ptr<B, decltype(deleter)> pb2(new B[2], deleter);
// //If you know the signature of your lambda function you can declare it with the function keyword directly instead of using auto
// function<void(B*)> fb = // YOUR LAMBDA
// //It is thus possible to declare the unique_ptr in one row
// unique_ptr<B, function<void(B*)> > pb1(new B[2], // YOUR LAMBDA
// //Note: In later standards its possible to specify the kind of pointer in the template parameter
// unique_ptr< B[] > pb(new B[2]); // Note B[]
return 0;
}