280 likes | 305 Views
The Standard Template Library. A brief introduction to the very expansive Standard Template Library (STL). Today’s Questions. Why should I use the STL? What is an std ::vector? How can I use an std ::vector? How does an std ::vector work?. Why use the STL?.
E N D
The Standard Template Library A brief introduction to the very expansive Standard Template Library (STL)
Today’s Questions • Why should I use the STL? • What is an std::vector? • How can I use an std::vector? • How does an std::vector work?
Why use the STL? • Writing templates can be difficult • Using templates is much easier and more productive • E.g. write your own sort function versus use a templated sort function • The STL has you covered • std::swap • std::sort • std::pair • std::min • And so much more!
The Containers Library • Several data structures are available • std::vector – a dynamic contiguous array of elements of some type • std::list – a doubly linked-list some type • The data structures are templated • std::vector<double> – a dynamic array that stores doubles • std::list<std::string> – a linked-list that stores std::strings http://en.cppreference.com/w/cpp/container
Motivating std::vector • We want to read integers from the user to an array until EOF • 1 -20 3 31 55 <Ctrl+D> • Then do some work on the array • Problem: How big of an array should we allocate? • We won’t know until after all the input is read. • Solution: linked list (std::list) • But lists are inefficient – accessing an element requires O(n) • Better Solution: an array that can grow dynamically (std::vector) • Accessing an element requires O(1)
Using std::vector – some of its member functions • Accessing elements • operator[] – same syntax as a C-style array • Inserting new elements • push_back(…) • Modifying existing elements • operator[] – still like a C-style array • Querying number of elements • size() int value = my_vector[42]; my_vector[42] = 64; http://en.cppreference.com/w/cpp/container/vector
Accepting Integer Input into a Vector #include <iostream> #include <vector> std::vector<int>get_integers(std::istream&stream){ std::vector<int> integers; int value; while(stream >> value){ integers.push_back(value); } return integers; } input_to_vector.cpp
Accepting Integer Input into a Vector Include header to use vector #include <iostream> #include <vector> std::vector<int>get_integers(std::istream&stream){ std::vector<int> integers; int value; while(stream >> value){ integers.push_back(value); } return integers; } Returns a vector of integers Calls vector’s default constructor: the vector is now empty input_to_vector.cpp
Accepting Integer Input into a Vector #include <iostream> #include <vector> std::vector<int>get_integers(std::istream&stream){ std::vector<int> integers; int value; while(stream >> value){ integers.push_back(value); } return integers; } Insert a new intelement into the vector. Will grow in size to accommodate new elements. input_to_vector.cpp
Printing a Vector’s Elements int main(){ std::vector<int> integers =get_integers(std::cin); for(std::size_typei=0;i<integers.size();++i){ std::cout<< integers[i]<<" "; } std::cout<<"\n"; } Use a for loop and print out each element in the vector. Remember that you can use operator[] and size()! input_to_vector.cpp
Printing a Vector’s Elements int main(){ std::vector<int> integers =get_integers(std::cin); for(inti=0;i<integers.size();++i){ std::cout<< integers[i]<<" "; } std::cout<<"\n"; } input_to_vector.cpp
Printing a Vector’s Elements int main(){ std::vector<int> integers =get_integers(std::cin); for(inti=0;i<integers.size();++i){ std::cout<< integers[i]<<" "; } std::cout<<"\n"; } size() returns size_t, which is unsigned intis signed Comparing signed and unsigned numbers will cause a compiler warning! input_to_vector.cpp warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
Printing a Vector’s Elements… Correctly int main(){ std::vector<int> integers =get_integers(std::cin); for(size_ti=0;i<integers.size();++i){ std::cout<< integers[i]<<" "; } std::cout<<"\n"; } input_to_vector.cpp
Vector Behind the Scenes Input: 1 3 8 7 2 <Ctrl + D> #include <iostream> #include <vector> std::vector<int>get_integers(std::istream&stream){ std::vector<int> integers; int value; while(stream >> value){ integers.push_back(value); } return integers; } integers int* array = intsize = 0 intcapacity = 3 ? ? ? Default constructor creates a contiguous array of capacity N input_to_vector.cpp
Vector Behind the Scenes Input: 1 3 8 7 2 <Ctrl + D> #include <iostream> #include <vector> std::vector<int>get_integers(std::istream&stream){ std::vector<int> integers; int value; while(stream >> value){ integers.push_back(value); } return integers; } integers int* array = intsize = 1 intcapacity = 3 ? ? 1 A new element is added, so the array is updated. Size increases by one. input_to_vector.cpp
Vector Behind the Scenes Input: 1 3 8 7 2 <Ctrl + D> #include <iostream> #include <vector> std::vector<int>get_integers(std::istream&stream){ std::vector<int> integers; int value; while(stream >> value){ integers.push_back(value); } return integers; } integers int* array = intsize = 2 intcapacity = 3 ? 3 1 A new element is added, so the array is updated. Size increases by one. input_to_vector.cpp
Vector Behind the Scenes Input: 1 3 8 7 2 <Ctrl + D> #include <iostream> #include <vector> std::vector<int>get_integers(std::istream&stream){ std::vector<int> integers; int value; while(stream >> value){ integers.push_back(value); } return integers; } integers int* array = intsize = 3 intcapacity = 3 8 3 1 A new element is added, so the array is updated. Size increases by one. input_to_vector.cpp
Vector Behind the Scenes Input: 1 3 8 7 2 <Ctrl + D> #include <iostream> #include <vector> std::vector<int>get_integers(std::istream&stream){ std::vector<int> integers; int value; while(stream >> value){ integers.push_back(value); } return integers; } integers int* array = intsize = 3 intcapacity = 3 8 ? ? ? ? 3 ? 1 ? A new element to add, but capacity == size. Create a new array of capacity 2*size, then copy the old array’s values into it. Delete the old array to avoid memory leaks. input_to_vector.cpp
Vector Behind the Scenes Input: 1 3 8 7 2 <Ctrl + D> #include <iostream> #include <vector> std::vector<int>get_integers(std::istream&stream){ std::vector<int> integers; int value; while(stream >> value){ integers.push_back(value); } return integers; } integers int* array = intsize = 3 intcapacity = 3 8 8 ? ? ? 3 3 1 1 A new element to add, but capacity == size. Create a new array of capacity 2*size, then copy the old array’s values into it. Delete the old array to avoid memory leaks. input_to_vector.cpp
Vector Behind the Scenes Input: 1 3 8 7 2 <Ctrl + D> #include <iostream> #include <vector> std::vector<int>get_integers(std::istream&stream){ std::vector<int> integers; int value; while(stream >> value){ integers.push_back(value); } return integers; } integers int* array = intsize = 3 intcapacity = 6 8 ? ? ? 3 1 A new element to add, but capacity == size. Create a new array of capacity 2*size, then copy the old array’s values into it. Delete the old array to avoid memory leaks. input_to_vector.cpp
Vector Behind the Scenes Input: 1 3 8 7 2 <Ctrl + D> #include <iostream> #include <vector> std::vector<int>get_integers(std::istream&stream){ std::vector<int> integers; int value; while(stream >> value){ integers.push_back(value); } return integers; } integers int* array = intsize = 4 intcapacity = 6 3 8 7 ? ? 1 Add new element to array. Size increases by one. input_to_vector.cpp
Vector Behind the Scenes Input: 1 3 8 7 2 <Ctrl + D> #include <iostream> #include <vector> std::vector<int>get_integers(std::istream&stream){ std::vector<int> integers; int value; while(stream >> value){ integers.push_back(value); } return integers; } integers int* array = intsize = 5 intcapacity = 6 3 8 7 2 ? 1 A new element is added, so the array is updated. Size increases by one. input_to_vector.cpp
Vector’s Algorithmic Complexity • Efficiently add elements with push_back() • When there isn’t enough space, capacity grows (usually by 2x) • So, even for a large number of N, push_back() will only generate a few array copies • On average push_back() has O(1) complexity
Vector’s Different Constructors std::vector<int> vec1;// default constructor. size = 0 std::vector<int> vec2(10);// size = 10, values unspecified std::vector<int> vec3(10,-1);// size = 10, all values -1 vector_constructors.cpp
Vectors Versus C-Style Arrays int* a =newint[10]; int* b =newint[10]; std::vector<int> v1(10), v2(10); // access elements the same way a[0]=5; v1[0]=5; // creating copies a = b; v1 = v2; // destroying delete[] a; delete[] b; • What happens when a = b? • Shallow copy – memory leak! • What happens when v1 = v2? • Deep copy – v2’s elements are copied to v1 • Do we need to delete v1 and v2? • No, they are not pointers • std::vector has a destructor, it will clean up after itself • Tip: avoid pointers, let std::vector manage memory for you. vector_versus_arrays.cpp
Bounds Checking with Vectors • operator[] does not create values • operator[] does not check bounds • Out-of-bounds indices will cause your program to crash! • For the milestones, you can use DebugCheck to do bounds checking • It will (also) make your program run more slowly std::vector<int> v1;// size 0 v1.push_back(-3);// size 1 v[0]=-2;// replace -3 with -2 v[1]=5;// ? vector_bounds_checking.cpp
Vector’s Algorithmic Complexity • Efficient random access to data with operator[] • Internally, the vector stores a contiguous data array • Accesses have O(1) complexity
Learning More About C++ and the STL • Books • Problem Solving in C++, Chapter 18 (Walter Savitch) • C++ Primer, Lippman, Lajoie, and Moo • Online • http://en.cppreference.com/w/ • http://www.cplusplus.com/ • Google