0% found this document useful (0 votes)
6 views

lecture3_initandref

Uploaded by

omarmatin2024
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views

lecture3_initandref

Uploaded by

omarmatin2024
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 76

Initialization &

References
Fun times!

1
Today
- Initialization
- Using auto
- References
- If time: Const

11
Definition

Initialization: How we
provide initial
values to variables

12
Reminder: Structs in Code
struct Student {
string name; // these are called fields
string state; // separate these by semicolons
int age;
};

Student s;
s.name = "Sarah";
s.state = "CA";
s.age = 21; // use . to access fields
13
Recall: Two ways to initialize a struct
Student s; // initialization after we declare
s.name = "Sarah";
s.state = "CA";
s.age = 21;
//is the same as ...
Student s = {"Sarah", "CA", 21};
// initialization while we declare

14
Multiple ways to initialize a pair...
std::pair<int, string> numSuffix1 = {1,"st"};
std::pair<int, string> numSuffix2;
numSuffix2.first = 2;
numSuffix2.second = "nd";
std::pair<int, string> numSuffix2 =
std::make_pair(3, "rd");
15
Definition

Uniform initialization: curly


bracket initialization. Available
for all types, immediate
initialization on declaration!

16
Uniform Initialization
std::vector<int> vec{1,3,5};
std::pair<int, string> numSuffix1{1,"st"};
Student s{"Sarah", "CA", 21};
// less common/nice for primitive types, but
possible!
int x{5};
string f{"Sarah"};

17
Careful with Vector initialization!
std::vector<int> vec1(3,5);
// makes {5, 5, 5}, not {3, 5}!
// uses a std::initializer_list (more later)
std::vector<int> vec2{3,5};
// makes {3, 5}

18
TLDR: use uniform
initialization to initialize
every field of your
non-primitive typed
variables - but be careful not
to use vec(n, k)!
19
Questions?

20
Today
- Initialization
- Using auto
- References
- If time: Const

21
Recap: Type Deduction with auto

22
Definition

auto: Keyword used in


lieu of type when
declaring a variable, tells
the compiler to deduce
the type.
23
Type Deduction using auto
// What types are these?
auto a = 3;
auto b = 4.3;
auto c = ‘X’;
auto d = “Hello”;
auto e = std::make_pair(3, “Hello”);

📝 auto does not mean that the variable doesn’t have a type.
It means that the type is deduced by the compiler.
24
Type Deduction using auto
// What types are these?
auto a = 3; // int
auto b = 4.3; // double
auto c = ‘X’; // char
auto d = “Hello”; // char* (a C string)
auto e = std::make_pair(3, “Hello”);
// std::pair<int, char*>
📝 auto does not mean that the variable doesn’t have a type.
It means that the type is deduced by the compiler.
25
‼ auto does not mean that
the variable doesn’t have a
type.
It means that the type is
deduced by the compiler.
26
When should we use auto?

27
Code Demo Recap!
quadratic.cpp

28
Radical
If Radical < 0, no real
roots

29
Quadratic: Typing these types out is a pain...
int main() {
int a, b, c;
std::cin >> a >> b >> c;
std::pair<bool, std::pair<double, double>> result =
quadratic(a, b, c);
bool found = result.first;
if (found) {
std::pair<double, double> solutions = result.second;
std::cout << solutions.first << solutions.second << endl;
} else {
std::cout << “No solutions found!” << endl;
}
}
30
Quadratic: Typing these types out is a pain...
int main() {
int a, b, c;
std::cin >> a >> b >> c; Cleaner! 🧼
auto result = quadratic(a, b, c);
bool found = result.first;
😊
if (found) {
auto solutions = result.second;
std::cout << solutions.first << solutions.second << endl;
} else {
std::cout << “No solutions found!” << endl;
}
}

31
Don’t overuse auto

32
Don’t overuse auto!
int main() {
auto a, b, c;
std::cin >> a >> b >> c;
auto result = quadratic(a, b, c);
bool found = result.first;
if (found) {
auto solutions = result.second;
std::cout << solutions.first << solutions.second << endl;
} else {
std::cout << “No solutions found!” << endl;
}
}

33
Can’t deduce the type b/c no value provided
int main() {
auto a, b, c; //compile error! ERROR!
std::cin >> a >> b >> c;
auto result = quadratic(a, b, c);
bool found = result.first;
if (found) {
auto solutions = result.second;
std::cout << solutions.first << solutions.second << endl;
} else {
std::cout << “No solutions found!” << endl;
}
}

34
For simple types (like bool) type it out
int main() {
int a, b, c; LESS CLEAR 👎☹
std::cin >> a >> b >> c;
auto result = quadratic(a, b, c);
auto found = result.first; //code less clear :/
if (found) {
auto solutions = result.second;
std::cout << solutions.first << solutions.second << endl;
} else {
std::cout << “No solutions found!” << endl;
}
}

35
Don’t overuse auto

...but use it to reduce long type names

36
Questions?

37
Structured Binding

38
Structured binding lets you initialize directly from
the contents of a struct
Before After
auto p = auto p =
std::make_pair(“s”, 5); std::make_pair(“s”, 5);
string a = p.first; auto [a, b] = p;
int b = p.second; // a is string, b is int
// auto [a, b] =
std::make_pair(...);

📝 This works for regular structs, too. Also, no nested structured binding. 39
A better way to use quadratic…
int main() {
int a, b, c;
std::cin >> a >> b >> c;
auto result = quadratic(a, b, c);
bool found = result.first;
if (found) {
auto solutions = result.second;
std::cout << solutions.first << solutions.second << endl;
} else {
std::cout << “No solutions found!” << endl;
}
}

40
Using Structured Binding
int main() {
int a, b, c;
std::cin >> a >> b >> c;
auto [found, solutions] = quadratic(a, b, c);
if (found) {
auto [x1, x2] = solutions;
std::cout << x1 << “ ” << x2 << endl;
} else {
std::cout << “No solutions found!” << endl;
}
}

📝 This is better is because it’s semantically clearer: variables have clear names.
41
Questions?

42
Today
- Initialization
- Using auto
- References
- If time: Const

43
Definition

Reference: An alias
(another name) for a
named variable

44
void changeX(int& x){ // changes to x will persist
x = 0;
}
void keepX(int x){
x = 0;
}
int a = 100;
int b = 100;
changeX(a); // a becomes a reference to x
keepX(b); // b becomes a copy of x
cout << a << endl; //0
cout << b << endl; //100
45
Standard C++ vector (intro)

46
Standard std::vector
std::vector<int> v;
std::vector<int> v(n, k);
v.push_back(k);
v[i] = k;
int k = v[i];

v.empty();
v.size();
v.clear();

47
References to variables
vector<int> original{1, 2};
vector<int> copy = original;
vector<int>& ref = original;
original.push_back(3);
copy.push_back(4);
ref.push_back(5);

cout << original << endl;


cout << copy << endl;
cout << ref << endl;
48
References to variables
vector<int> original{1, 2};
vector<int> copy = original;
vector<int>& ref = original;
original.push_back(3);
copy.push_back(4);
ref.push_back(5);

cout << original << endl; // {1, 2, 3, 5}


cout << copy << endl;
cout << ref << endl;
49
References to variables
vector<int> original{1, 2};
vector<int> copy = original;
vector<int>& ref = original;
original.push_back(3);
copy.push_back(4);
ref.push_back(5);

cout << original << endl; // {1, 2, 3, 5}


cout << copy << endl; // {1, 2, 4}
cout << ref << endl;
50
References to variables
vector<int> original{1, 2};
vector<int> copy = original;
vector<int>& ref = original;
original.push_back(3);
copy.push_back(4);
ref.push_back(5);

cout << original << endl; // {1, 2, 3, 5}


cout << copy << endl; // {1, 2, 4}
cout << ref << endl; // {1, 2, 3, 5}
51
References to variables
vector<int> original{1, 2};
vector<int> copy = original; “=” automatically makes
vector<int>& ref = original; a copy! Must use & to
original.push_back(3); avoid this.
copy.push_back(4);
ref.push_back(5);

cout << original << endl; // {1, 2, 3, 5}


cout << copy << endl; // {1, 2, 4}
cout << ref << endl; // {1, 2, 3, 5}
52
The classic reference-copy bug 1.0:
void shift(vector<std::pair<int, int>>& nums) {
for (size_t i = 0; i < nums.size(); ++i) {
auto [num1, num2] = nums[i];
num1++;
num2++;
}
}

53
The classic reference-copy bug 1.0:
void shift(vector<std::pair<int, int>>& nums) {
for (size_t i = 0; i < nums.size(); ++i) {
auto [num1, num2] = nums[i];
num1++; ++i: increment then return
size_t is commonly used for
i++: return then increment
indicesnum2++;
because it’s unsigned
In for loops, both work the
and dynamically sized (using
} same and no performance
sizeof()). Nitty gritty
difference anymore so use
} what you prefer! Nitty gritty

54
The classic reference-copy bug 1.0:
void shift(vector<std::pair<int, int>>& nums) {
for (size_t i = 0; i < nums.size(); ++i) {
auto [num1, num2] = nums[i];
num1++;
num2++;
2 min: THINK, PAIR, SHARE!
}
}

55
The classic reference-copy bug 1.0:
void shift(vector<std::pair<int, int>>& nums) {
for (size_t i = 0; i < nums.size(); ++i) {
auto [num1, num2] = nums[i];
num1++;
num2++;
} This creates a copy of the
} course
This is updating that same
copy!

56
The classic reference-copy bug 1.0: Fixed
void shift(vector<std::pair<int, int>>& nums) {
for (size_t i = 0; i < nums.size(); ++i) {
auto& [num1, num2] = nums[i];
num1++;
num2++;
}
}

57
The classic reference-copy bug 2.0:
void shift(vector<std::pair<int, int>>& nums) {
for (auto [num1, num2]: nums) {
num1++;
num2++;
}
}

58
The classic reference-copy bug 2.0:
void shift(vector<std::pair<int, int>>& nums) {
for (auto [num1, num2]: nums) {
num1++;
num2++;
}
This creates a copy of the
} course
This is updating that same
copy!

59
The classic reference-copy bug 2.0, fixed:
void shift(vector<std::pair<int, int>>& nums) {
for (auto& [num1, num2]: nums) {
num1++;
num2++;
}
}

60
Definition: l-values vs r-values
- l-values can appear on the
left or right of an =
- x is an l-value

int x = 3;
int y = x;

l-values have names


l-values are not
temporary
61
Definition: l-values vs r-values
- l-values can appear on the - r-values can ONLY appear on
left or right of an = the right of an =
- x is an l-value - 3 is an r-value

int x = 3; int x = 3;
int y = x; int y = x;

l-values have names


r-values don’t have names
l-values are not
r-values are temporary
temporary
62
The classic reference-rvalue error
void shift(vector<std::pair<int, int>>& nums) {
for (auto& [num1, num2]: nums) {
num1++;
num2++;
}
}

shift({{1, 1}});

63
The classic reference-rvalue error
void shift(vector<std::pair<int, int>>& nums) {
for (auto& [num1, num2]: nums) {
num1++;
num2++;
}
}

shift({{1, 1}});
// {{1, 1}} is an rvalue, it can’t be referenced
64
The classic reference-rvalue error, fixed
void shift(vector<pair<int, int>>& nums) {
for (auto& [num1, num2]: nums) {
num1++;
num2++;
}
}
auto my_nums = {{1, 1}};
shift(my_nums);

65
Note: You can only create references to variables

int& thisWontWork = 5; // This doesn't work!

66
Questions?

67
Today
- Initialization
- Using auto
- References
- If time: Const

68
BONUS: Const and Const References

69
const indicates a variable can’t be modified!
const variables can be references or not!

std::vector<int> vec{1, 2, 3};


const std::vector<int> c_vec{7, 8}; // a const variable
std::vector<int>& ref = vec; // a regular reference
const std::vector<int>& c_ref = vec; // a const reference

vec.push_back(3);
c_vec.push_back(3);
ref.push_back(3);
c_ref.push_back(3);
70
const indicates a variable can’t be modified!
const variables can be references or not!

std::vector<int> vec{1, 2, 3};


const std::vector<int> c_vec{7, 8}; // a const variable
std::vector<int>& ref = vec; // a regular reference
const std::vector<int>& c_ref = vec; // a const reference

vec.push_back(3); // OKAY
c_vec.push_back(3);
ref.push_back(3);
c_ref.push_back(3);
71
const indicates a variable can’t be modified!
const variables can be references or not!

std::vector<int> vec{1, 2, 3};


const std::vector<int> c_vec{7, 8}; // a const variable
std::vector<int>& ref = vec; // a regular reference
const std::vector<int>& c_ref = vec; // a const reference

vec.push_back(3); // OKAY
c_vec.push_back(3); // BAD - const
ref.push_back(3);
c_ref.push_back(3);
72
const indicates a variable can’t be modified!
const variables can be references or not!

std::vector<int> vec{1, 2, 3};


const std::vector<int> c_vec{7, 8}; // a const variable
std::vector<int>& ref = vec; // a regular reference
const std::vector<int>& c_ref = vec; // a const reference

vec.push_back(3); // OKAY
c_vec.push_back(3); // BAD - const
ref.push_back(3); // OKAY
c_ref.push_back(3);
73
const indicates a variable can’t be modified!
const variables can be references or not!

std::vector<int> vec{1, 2, 3};


const std::vector<int> c_vec{7, 8}; // a const variable
std::vector<int>& ref = vec; // a regular reference
const std::vector<int>& c_ref = vec; // a const reference

vec.push_back(3); // OKAY
c_vec.push_back(3); // BAD - const
ref.push_back(3); // OKAY
c_ref.push_back(3); // BAD - const
74
Can’t declare non-const reference to const variable!
const std::vector<int> c_vec{7, 8}; // a const variable

// BAD - can't declare non-const ref to const vector


std::vector<int>& bad_ref = c_vec;

75
Can’t declare non-const reference to const variable!
const std::vector<int> c_vec{7, 8}; // a const variable

// fixed
const std::vector<int>& bad_ref = c_vec;

76
Can’t declare non-const reference to const variable!
const std::vector<int> c_vec{7, 8}; // a const variable

// fixed
const std::vector<int>& bad_ref = c_vec;

// BAD - Can't declare a non-const reference as equal


// to a const reference!
std::vector<int>& ref = c_ref;

77
const & subtleties
std::vector<int> vec{1, 2, 3};
const std::vector<int> c_vec{7, 8};

std::vector<int>& ref = vec;


const std::vector<int>& c_ref = vec;

auto copy = c_ref; // a non-const copy


const auto copy = c_ref; // a const copy
auto& a_ref = ref; // a non-const reference
const auto& c_aref = ref; // a const reference

78
Remember: C++, by default, makes
copies when we do variable
assignment! We need to use & if we
need references instead.

79
When do we use references/const references?
- If we’re working with a variable that takes up little
space in memory (e.g. int, double), we don’t need to
use a reference and can just copy the variable
- If we need to alias the variable to modify it, we can
use references
- If we don’t need to modify the variable, but it’s a big
variable (e.g. std::vector), we can use const references

80
You can return references as well!
// Note that the parameter must be a non-const reference to return
// a non-const reference to one of its elements!
int& front(std::vector<int>& vec) {
// assuming vec.size() > 0
return vec[0];
}

int main() {
std::vector<int> numbers{1, 2, 3};
front(numbers) = 4; // vec = {4, 2, 3}
return 0;
}
81
Can also return const references
const int& front(std::vector<int>& vec) {
// assuming vec.size() > 0
return vec[0];
}

82
Questions?

83
Recap:
- Uniform Initialization
- A “uniform” way to initialize variables of
different types!
- References
- Allow us to alias variables
- Const
- Allow us to specify that a variable can’t be
modified
84
Thanks for coming!
Next time: Streams!

85

You might also like