containers and Iterators in C++

Iterators

class MyContainer{
public:
    const int* array;
    int size;
    class Iterator{
        const int *obj;
    public:
        Iterator(const int* obj):obj(obj){
        }

        bool operator !=(Iterator other){
            cout<<"call != \n";
            if(other.obj==this->obj)
                return false;
            return true;
        }

        Iterator operator++(){
            obj++;
            cout<<"call ++ \n";
            return *this;
        }

        const int& operator*()const {
            cout<<"call * \n";
            return *obj;
        }

    };
    template <int i>
    MyContainer(int const (&obj)[i]):array(obj),size(i){

    }

    Iterator begin(){
        MyContainer::Iterator iterator(this->array);
        cout<<"call begin\n";
        return iterator;
    }

    Iterator end() {
        MyContainer::Iterator iterator(this->array+size);
        cout << "call begin\n";
        return iterator;

    }
};

int main(int argc,char* argv[]){
    MyContainer mc({1,2,3,4,5,6});
    for(const auto& vv:mc){
        cout<<vv<<endl;
    }

    return 0;
}

simple forward iterator and the result is

call begin
call !=
call *
1
call ++
call !=
call *
2
call ++
call !=
call *
3
call ++
call !=
call *
4
call ++
call !=
call *
5
call ++
call !=
call *
6
call ++
call !=

Iterator categoryPropertiesContainer
Forward iterator++It, It++, *Itunordered associative container
 It == It2, It != It2std::forward_list
Bidirectional iterator--It, It--ordered associative container
  std::list
Random access iteratorIt[i]std::array
 It+= n, It-= nstd::vector
 It+n, It-nstd::deque
 n+Itstd::string
 It-It2 
 It < It2, It <= It2, It > It2 
 It >= It2 
Global functionDescription
std::begin(cont)Returns a begin iterator to the container cont.
std::end(cont)Returns an end iterator to the container cont.
std::rbegin(cont)Returns a reverse begin iterator to the container cont.
std::rend(cont)Returns a reverse end iterator to the container cont.
std::cbegin(cont)Returns a constant begin iterator to the container cont.
std::cend(cont)Returns a constant end iterator to the container cont.
std::crbegin(cont)Returns a reverse constant begin iterator to the container cont.
std::crend(cont)Returns a reverse constant end iterator to the container cont.
std::prev(it)Returns an iterator, which points to a position before it
std::next(it)Returns an iterator, which points to a position after it.
std::distance(fir, sec)Returns the number of elements between fir and sec.
std::advance(it, n)Puts the iterator it n positions further.
general functions
// iteratorUtilities.cpp
...
#include <iterator>
...
using std::cout;

std::unordered_map<std::string, int> myMap{{"Rainer", 1966}, {"Beatrix", 1966},
                                           {"Juliette", 1997}, {"Marius", 1999}};

for (auto m: myMap) cout << "{" << m.first << "," << m.second << "} ";
     // {Juliette,1997},{Marius,1999},{Beatrix,1966},{Rainer,1966}

auto mapItBegin= std::begin(myMap);
cout << mapItBegin->first << " " << mapItBegin->second; // Juliette 1997

auto mapIt= std::next(mapItBegin);
cout << mapIt->first << " " << mapIt->second;            // Marius 1999
cout << std::distance(mapItBegin, mapIt);                 // 1

std::array<int, 10> myArr{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
for (auto a: myArr) std::cout << a << " ";               // 0 1 2 3 4 5 6 7 8 9

auto arrItEnd= std::end(myArr);
auto arrIt= std::prev(arrItEnd);
cout << *arrIt << std::endl;                             // 9

std::advance(arrIt, -5);
cout << *arrIt;                                          // 4

Containers

The table shows you the constructors and destructors of a container. A std:vector stands for the rest of them.

TypeExample
Defaultstd::vector<int> vec1
Rangestd::vector<int> vec2(vec1.begin(), vec1.end())
Copystd::vector<int> vec3(vec2)
Copystd::vector<int> vec3= vec2
Movestd::vector<int> vec4(std::move(vec3))
Movestd::vector<int> vec4= std::move(vec3)
Sequence (Initializer list)std::vector<int> vec5 {1, 2, 3, 4, 5}
Sequence (Initializer list)std::vector<int> vec5= {1, 2, 3, 4, 5}
  
Destructorvec5.~vector()
Delete elementsvec5.clear()

Because std::array is generated at compile time, there are a few things that are special. std::array has no move constructor and can neither be created with a range nor with an initialiser list. However, you can initialize a std::array with an aggregate initialisation. Also, std::array has no method for removing its elements.

#include <map>
#include <unordered_map>
#include <vector>
...
using namespace std;

vector<int> vec= {1, 2, 3, 4, 5, 6, 7, 8, 9};
map<string, int> m= {{"bart", 12345}, {"jenne", 34929}, {"huber", 840284} };
unordered_map<string, int> um{m.begin(), m.end()};

for (auto v: vec) cout << v << " "; // 1 2 3 4 5 6 7 8 9
for (auto p: m) cout << p.first << "," << p.second << " ";
                                    // bart,12345 huber,840284 jenne,34929
for (auto p: um) cout << p.first << "," << p.second << " ";
                                    // bart,12345 jenne,34929 huber,840284

vector<int> vec2= vec;
cout << vec.size() << endl; // 9
cout << vec2.size() << endl; // 9

vector<int> vec3= move(vec);
cout << vec.size() << endl; // 0
cout << vec3.size() << endl; // 9

vec3.clear();
cout << vec3.size() << endl; // 0

size+empty+max_size

#include <map>
#include <set>
#include <vector>
...
using namespace std;

vector<int> intVec{1, 2, 3, 4, 5, 6, 7, 8, 9};
map<string, int> str2Int = {{"bart", 12345}, 
                            {"jenne", 34929}, {"huber", 840284}};
set<double> douSet{3.14, 2.5};

cout << intVec.empty() << endl;  // false
cout << str2Int.empty() << endl; // false
cout << douSet.empty() << endl;  // false

cout << intVec.size() << endl;  // 9
cout << str2Int.size() << endl; // 3
cout << douSet.size() << endl;  // 2

cout << intVec.max_size() << endl;  // 4611686018427387903
cout << str2Int.max_size() << endl; // 384307168202282325
cout << douSet.max_size() << endl;  // 461168601842738790

std::copy

template<class InputIterator, class OutputIterator>
  OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result)
{
  while (first!=last) {
    *result = *first;
    ++result; ++first;
  }
  return result;
}

access

IteratorDescription
cont.begin() and cont.end()Pair of iterators to iterate forward.
cont.cbegin() and cont.cend()Pair of iterators to iterate const forward.
cont.rbegin() and cont.rend()Pair of iterators to iterate backward.
cont.crbegin() and cont.crend()Pair of iterators to iterate const backward.

assign new elements
You can assign new elements to existing containers or swap two containers. For the assignment of a container cont2 to a container cont, there exists the copy assignment cont= cont2 and the move assignment cont= std::move(cont2). A special form of assignment is the one with an initialiser list: cont= {1, 2, 3, 4, 5}. That’s not possible for std::array, but you can instead use the aggregate initialisation. The function swap exists in two forms. You have it as a method cont(swap(cont2)) or as a function template std::swap(cont, cont2).

comparison operators
Containers support the comparison operators ==!=<><=>=. The comparison of two containers happens on the elements of the containers. If you compare associative containers, their key is compared. Unordered associative containers support only the comparison operator == and !=.

Sequential Container

Criteriaarrayvectordequelistforward_list
Sizestaticdynamicdynamicdynamicdynamic
Implementationstatic arraydynamic arraysequence of arraysdoubled linked listsingle linked list
Accessrandomrandomrandomforward and backwardforward
Optimized for insert and delete at end: O(1)begin and end: O(1)begin and end: O(1)begin(1)
    arbitrary: O(1)arbitrary: O(1)
Memory reservation yesnonono
Release of memory shrink_to_fitshrink_to_fitalwaysalways
Strengthno memory allocation; minimal memory requirements95% solutioninsertion and deletion at the begin and endinsertion and deletion at an arbitrary positionfast insertion and deletion; minimal memory requirements
Weaknessno dynamic memoryInsertion and deletionInsertion and deletionno random accessno random access
 memory allocationat an arbitrary position: O(n)at an arbitrary position: O(n)  
vector

std::vector is a homogeneous container, for which it’s length can be adjusted at runtime. std::vector needs the header <vector>. As it stores its elements contiguously in memory, std::vector support pointer arithmetic.

deque

std::deque, which consists of a sequence of arrays, is quite similar to std::vectorstd::deque need the header <deque>. The std::deque has three additional methods deq.push_front(elem)deq.pop_front() and `deq.emplace_front(args… ) to add or remove elements at its beginning.

list

std::list is a doubled linked list. std::list needs the header <list>.

Although it has a similar interface to std::vector or std::dequestd::list is quite different to both of them. That’s due to its structure.

Associative Container

Associative containerSortedAssociated valueMore identical keysAccess time
std::setyesnonologarithmic
std::unordered_setnononoconstant
std::mapyesyesnologarithmic
std::unordered_mapnoyesnoconstant
std::multisetyesnoyeslogarithmic
std::unordered_multisetnonoyesconstant
std::multimapyesyesyeslogarithmic
std::unordered_multimapnoyesyesconstant

Adaptors for Containers

stack

...
#include <stack>
...
std::stack<int> myStack;

std::cout << myStack.empty() << std::endl;   // true
std::cout << myStack.size() << std::endl;    // 0

myStack.push(1);
myStack.push(2);
myStack.push(3);
std::cout << myStack.top() << std::endl;     // 3

while (!myStack.empty()){ 
  std::cout << myStack.top() << " ";
  myStack.pop();
}                                            // 3 2 1

std::cout << myStack.empty() << std::endl;   // true
std::cout << myStack.size() << std::endl;    // 0

queue

...
#include <queue>
...
std::queue<int> myQueue;

std::cout << myQueue.empty() << std::endl;    // true
std::cout << myQueue.size() << std::endl;     // 0

myQueue.push(1);
myQueue.push(2);
myQueue.push(3);
std::cout << myQueue.back() << std::endl;     // 3
std::cout << myQueue.front() << std::endl;    // 1

while (!myQueue.empty()){
  std::cout << myQueue.back() << " ";
  std::cout << myQueue.front() << " : ";
  myQueue.pop();
}                                             // 3 1 : 3 2 : 3 3

std::cout << myQueue.empty() << std::endl;    // true
std::cout << myQueue.size() << std::endl;     // 0

priority_queue 

#include <queue>
...
std::priority_queue<int> myPriorityQueue;

std::cout << myPriorityQueue.empty() << std::endl;   // true
std::cout << myPriorityQueue.size() << std::endl;    // 0

myPriorityQueue.push(3);
myPriorityQueue.push(1);
myPriorityQueue.push(2);
std::cout << myPriorityQueue.top() << std::endl;     // 3

while (!myPriorityQueue.empty()){
  std::cout << myPriorityQueue.top() << " ";
  myPriorityQueue.pop();
}                                                    // 3 2 1

std::cout << myPriorityQueue.empty() << std::endl;   // true
std::cout << myPriorityQueue.size() << std::endl;    // 0

std::priority_queue<std::string, std::vector<std::string>,
                    std::greater<std::string>> myPriorityQueue2;

myPriorityQueue2.push("Only");
myPriorityQueue2.push("for");
myPriorityQueue2.push("testing");
myPriorityQueue2.push("purpose");
myPriorityQueue2.push(".");

while (!myPriorityQueue2.empty()){
  std::cout << myPriorityQueue2.top() << " ";
  myPriorityQueue2.pop();
}                                // . Only for purpose testing

back_inserter + front_inserter + inserter

#include <iterator>
...
std::deque<int> deq{5, 6, 7, 10, 11, 12};
std::vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};

std::copy(std::find(vec.begin(), vec.end(), 13),
          vec.end(), std::back_inserter(deq));

for (auto d: deq) std::cout << d << " ";
                    // 5 6 7 10 11 12 13 14 15

std::copy(std::find(vec.begin(), vec.end(), 8),
std::find(vec.begin(), vec.end(), 10),
std::inserter(deq,
std::find(deq.begin(), deq.end(), 10)));d
for (auto d: deq) std::cout << d << " ";
                    // 5 6 7 8 9 10 11 12 13 14 15

std::copy(vec.rbegin()+11, vec.rend(),
std::front_inserter(deq));
for (auto d: deq) std::cout << d << " ";
                    // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

How To Read Diodes Datasheet

Zener

Voltage Vz:   The Zener voltage or reverse voltage specification of the diode is often designated by the letters Vz.

Current :   The current, IZM, of a Zener diode is the maximum current that can flow through a Zener diode at its rated voltage, VZ.
Typically there is also a minimum current required for the operation of the diode. As a rough rule of thumb, this can be around 5 to 10 mA for a typical leaded 400 mW device. Below this current level, the diode does not break down adequately to maintain its stated voltage.
It is best to keep the Zener diode running above this minimum value with some margin, but without the likelihood of it dissipating too much power when the Zener needs to pass more current.

Power rating:   All Zener diodes have a power rating that should not be exceeded. This defines the maximum power that can be dissipated by the package, and it is the product of the voltage across the diode multiplied by the current flowing through it.

Zener resistance Rz:   The IV characteristic of the Zener diode is not completely vertical in the breakdown region. This means that for slight changes in current, there will be a small change in the voltage across the diode. The voltage change for a given change in current is the resistance of the diode. This value of resistance, often termed the resistance is designated Rz.

 Zener diode resistance shown as slope of breakdown area
Zener diode resistance

The inverse of the slope shown is referred to as the dynamic resistance of the diode, and this parameter is often noted in the manufacturers’ datasheets. Typically the slope does not vary much for different current levels, provided they are between about 0.1 and 1 times the rated current Izt.

Voltage tolerance:   With diodes being marked and sorted to meet the E12 or E24 value ranges, typical tolerance specifications for the diode are ±5%. Some datasheets may specify the voltage as a typical voltage and then provide a maximum and minimum.

How to use a Zener Diode

As said a Zener diode will mostly be used in a protection circuit or in a crude voltage regulator circuit. Either way, it very important to remember that a Zener diode should always be used along with a Zener resistor.

Zener resistor is nothing but an ordinary resistor which is used for current limiting purpose. This resistor decides (limits) the amount of current that can flow through the Zener diode or through the load connected to Zener diode; this was the Zener diode is protected from high current. If this resistor is not used the diode will be damaged due to high current. A simple Zener diode circuit is shown below.

Zener Diode Circuit

In the above circuit the formulae to calculate the Zener series resistor Rs is shown below

Rs = (Vs – Vz) / Iz

For a 1N4732A Zener diode the value of Vz is 4.7V and Pz is 500mW as mentioned in specifications above, now with supply voltage (Vs) of 12V the value of Rs will be

Rs = (12-4.7)/Iz
Iz = Pz/Vz = 500mW / 4.7V = ~106mA
Therefore, Rs = (12-4.7)/106 = 68 ohms
Rs = 68ohms (approx)

Diode 

Semiconductor material:
Silicon:   The forward turn on voltage is around 0.6V, which is high for some applications, although for Schottky diodes it is less.

Germanium:   Germanium is less widely used and but offers a low turn on voltage of around 0.2 to 0.3 V.

Diode type:  Zener diodes are used for providing reference voltages, whilst varactor diodes are used to provide a variable level of capacitance in an RF design according to the reverse bias provided. Rectifier diodes may use a straightforward PN junction diode, or in some cases they may use a Schottky diode for a lower forward voltage. Whatever the application is is necessary to use the right type of diode to obtain the required functionality and performance.

Forward voltage drop, Vf:   Any electronics device passing current will develop a resulting voltage across it and this diode characteristic is of great importance, especially for power rectification where power losses will be higher for a high forward voltage drop. Also diodes for RF designs often need a small forward voltage drop as signals may be small but still need to overcome it.

Reverse breakdown voltage, V(BR)R:   This is a little different to the peak inverse voltage in that this voltage is the point at which the diode will break down.

Maximum forward current If:   For an electronic circuit design that passes any levels of current it is necessary to ensure that the maximum current levels for the diode are not exceeded. As the current levels rise, so additional heat is dissipated and this needs to be removed.

Leakage current Ir:   If a perfect diode were available, then no current would flow when it was reverse biased. It is found that for a real PN junction diode, a very small amount of current flow in the reverse direction as a result of the minority carriers in the semiconductor. The level of leakage current is dependent upon three main factors. The reverse voltage is obviously significant. It is also temperature dependent, rising appreciably with temperature. It is also found that it is very dependent upon the type of semiconductor material used – silicon is very much better than germanium.

IV characteristic of a PN junction diode showing the reverse leakage current parameter
PN diode IV characteristic showing the leakage current parameter

The leakage current characteristic or specification for a PN junction diode is specified at a certain reverse voltage and particular temperature. The specification is normally defined in terms of in microamps, µA or picoamps, pA as the levels are normally very low before reverse breakdown occurs.

CHARACTERISTICTYPICAL VALUEUNITDETAILS
Max DC Blocking Voltage, Vr70V
Max forward continuous current, Ifm15mA
Reverse breakdown voltage, V(BR)R70V@ reverse current of 10µA
Reverse leakage current, IR200µAAt VR=50V
Forward voltage drop, VF0.41

1.00
Vat IF = 1.0 mA

IF=15mA
Junction capacitance, Cj2.0pFVR = 0V, f=1MHz
Reverse recovery time, trr1nS
1N5711 

How To Read Transistors Datasheet

Mosfets

Type of Control Channel: N Or P Channel
Vds : Maximum Drain-Source Voltage
Pd : Maximum Power Dissipation
Vgs : Maximum Gate-Source Voltage
Id : Maximum Drain Current
tr : Rise Time 0.01 ns for example
Cd : drain-source capacitance for example 600 pf
Rds : maximum drain-source on-state resistance 0.01 ohm for example

In a power MOSFET, the gate is insulated by a thin silicon oxide. Therefore, a power MOSFET has capacitances between the gate-drain, gate-source and drain-source terminals as shown in

BJT

Polarity: NPN
Pc : Maximum Collector Power Dissipation
Vcb : Maximum Collector-Base Voltage
Vce : Maximum Collector-Emitter Voltage
Veb : Maximum Emitter-Base Voltage
Ic : Maximum Collector Current
ft : Transition Frequency The transition frequency describes how the transistor’s current gain is affected by the input frequency. This is a low pass effect, so frequencies beyond 600 kHz on the original part or 4 MHz on the new one would start to be attenuated. Audible frequency range is 20 Hz – 20 kHz which is far below the transition frequency of both parts. No effects should be noticeable
Cc : Collector Capacitance
hfe : Forward Current Transfer Ratio