Tuesday, January 21, 2014

C++ Code snippets

  1. Pre increment and Post increment: Difference

    Pre increment: ++i
    int i, x;
    i = 2;
    x = ++i;
    // now x = 3, i = 3 (x got assigned the incremented valued of i)
    
    Post increment: i++
    int i, x;
    i = 2;
    x = i++; 
    // now x = 2, but i = 3 (x got assigned the value of i (i.e. 2) and then i was incremented)
    
  2. For loop: Sequence of events
    for(Initialization; Condition; Increase)
    {
        Statement;
    }
    
    1. Initialization is executed. Generally, this declares a counter variable, and sets it to some initial value. This is executed a single time, at the beginning of the loop.
    2. Condition is checked. If it is true, the loop continues; otherwise, the loop ends.
    3. Statement is executed.
    4. Increase is executed, and the loop gets back to step 2.
    Because (2) and (4) are decoupled, either pre or post-increment can be used.

    The three fields in a for-loop are optional. They can be left empty, but in all cases the semicolon signs between them are required.
    For example, for( ;n<10; ) is a loop without initialization or increase (equivalent to a while-loop); and for( ;n<10; ++n) is a loop with increase, but no initialization (maybe because the variable was already initialized before the loop). A loop with no condition is equivalent to a loop with true as condition (i.e., an infinite loop).

  3. Delete NULL pointer
    Is it safe to call delete on a NULL pointer? Or in other words, do I need to check for non null pointer before calling delete?
    Yes it is safe to call delete. You do not need to check for null pointer before deleting.

    From the C++0x draft Standard.
    $5.3.5/2 - "[...]In either alternative, the value of the operand of delete may be a null pointer value.[...'"

  4. String: Remove the first occurrence of a character in string
    std::string myString;
    auto pos = myString.find('d');
    if(pos != std::string::npos)
    {
        myString.erase(pos, 1);
    }
    

  5. String: Remove all occurrences of a character in string
    std::string myString;
    myString.erase(std::remove(myString.begin(), myString.end(), 'd'), myString.end());
    

  6. String: Get the last element in string
    std::string myString;
    char ch = *myString.rbegin();
    

  7. String: Find the last occurrence of a character in string
    std::string myString;
    unsigned found = myString.find_last_of(":");
    

  8. String: Extract the end string after the last occurrence of a string
    std::string myString;
    unsigned found = myString.find_last_of(":");
    myString.substr(found+1);
    

  9. String: Get the string between two delimiters in string
    std::string myString;
    unsigned first = myString.find(START_DELIMITER);
    unsigned last = myString.find(END_DELIMITER);
    std::string newString = myString.substr(first, last-first);
    

  10. String: Count the number of occurrences of a character
    std::string myString = "a_b_c";
    int count = std::count(myString.begin(), myString.end(), '_');
    

  11. Length of array
    sizeof(list)/sizeof(list[0]);
    
    OR
    
    int a[7];
    std::cout << "Length of array = " << (sizeof(a)/sizeof(*a)) << std::endl;  
    This doesn't work on pointers, though, i.e. it won't work for either of the following:  
    int *p = new int[7]; 
    std::cout << "Length of array = " << (sizeof(p)/sizeof(*p)) << std::endl;
    
    or
    
    void func(int *p) 
    {     
        std::cout << "Length of array = " << (sizeof(p)/sizeof(*p)) << std::endl; 
    }  
    int a[7]; 
    func(a); 
    
  12. Convert Array to Vector
    int array[] = {1, 2, 3};
    int size = sizeof array / sizeof *array;
    std::vector vec(array, array + size);
    
    OR
    
    int myArray[3]={1, 2, 3};
    std::vector myVec(myArray, myArray + sizeof myArray / sizeof myArray[0]);
    test(myVec);
    
  13. Convert Vector to Array
    std::vector myVec;
    if(myVec.size() > 0)
    {
        double* myArray = &myVec[0];    //Would cause "vector subscript out of range" runtime error if vector size is not  
    }                                   //greater than zero, because it tries to access the first (zeroth) element of vector
    
  14. Vector: Get iterator from index
    vector::iterator nthIter = myVec.begin() + index;
    
  15. Vector: Get index from iterator
    std::vector myVec;
    int index = iter - myVec.begin();
    
  16. Vector: Remove an element
    The standard sequence-container erase-remove idiom:
    myVec.erase(std::remove(myVec.begin(), myVec.end(), value_to_remove), myVec.end());
    
    Erasing invalidates iterators and references at or after the point of the erase, including the end() iterator.
    Erase returns a new iterator that points to the element immediately after the element(s) that were erased (or to the end if there is no such element).
    For example the vector had elements {1, 2, 3, 3, 4, 5} and you want to remove 3. You start iterating and the moment it finds the first 3, erase will remove it from the vector, but it will return an iterator to the next element after the first 3 (i.e. the next 3). So during the nest iteration after erase, the iterator would have been bumped up twice and hence during the next iteration it will skip removing the next 3. Result will be {1, 2, 3, 4, 5}
    What happens during remove is that remove compacts the elements that differ from the value to be removed (value_to_remove)
    to the beginning of the vector and returns the iterator to the first element after that range. The elements substituted in place of value_to_remove at the end after compacting are unspecified. So, using remove the vector becomes {1, 2, 4, 5, ?, ?} and it return a pointer to the first "?". Then erase is used in the range from the first "?" to the end of the vector, so it removes all these elements (who's value is unspecified). So now the vector becomes {1, 2, 4, 5}
  17. Vector: Check if it contains duplicate elements
    First std::sort.
    Then  std::unique.
    
    std::sort(myVec.begin(), myVec.end());
    bool hasDuplicateElements = std::unique(myVec.begin(), myVec.end()) != myVec.end();
    
    //Getting a new container with no duplicates
    std::unique_copy(myVec.begin(), myVec.end(), std::back_inserter(newMyVec));
    
    //Remove duplicates from a vector
    std::sort(myVec.begin(), myVec.end());
    myVec.erase(std::unique(myVec.begin(), myVec.end()), myVec.end());
    
  18. Vector: set_symmetric_difference

    std::sort(firstVec.begin(), firstVec.end());
    std::sort(secondVec.begin(), secondVec.end());
    
    set_symmetric_difference(firstVec, firstVec, secondVec, secondVec, std::back_inserter(symmetricDifferenceVec));
    
  19. Vector: set_difference

    std::sort(firstVec.begin(), firstVec.end());
    std::sort(secondVec.begin(), secondVec.end());
    
    set_difference(firstVec, firstVec, secondVec, secondVec, std::back_inserter(symmetricDifferenceVec));
    
  20. Set: Check if an element being inserted is already present
    Elements in a set are unique. For a similar container allowing for duplicate elements use multiset.
    std::set mySet;
    mySet.insert(11);
    mySet.insert(22);
    
    if(!(mySet.insert(11)).second)
    {
        cout << "Element is already present in Set and will not be inserted" << endl;
    }
    
  21. Map: View a Map
    std::map<string,int> myMap;
    for(std::map<string,int>::iterator iter = myMap.begin(); iter != myMap.end(); ++iter)
    {
        cout << "String = " << iter->first << endl;
        cout << "Integer = " << iter->second << endl;
    }
    
  22. Map: Free up memory of a map of pointers
    std::map<int, A*> myMap;
    
    A* obj_A1 = new A;
    A* obj_A2 = new A;
    A* obj_A3 = new A;
    
    myMap.insert(std::make_pair(11, obj_A1));
    myMap.insert(std::make_pair(22, obj_A2));
    myMap.insert(std::make_pair(33, obj_A3));
    
    delete myMap[11];
    delete myMap[22];
    delete myMap[33];
    
    OR
    
    for(std::map<int, A*>::iterator iter = myMap.begin(); iter != myMap.end(); ++it)
    {
        delete iter->second;
    }
    
  23. Map: Obtain the previous value by iterating
    map<int, std::string> myMap;
    myMap.insert(make_pair(11, "Cello"));
    myMap.insert(make_pair(22, "Hello"));
    myMap.insert(make_pair(33, "Jello"));
    
    for(map<int, string>::iterator iter = myMap.begin(); iter != myMap.end(); ++iter)
    {
        if(iter != myMap.begin())    //Need to check if iterator is not the first one, because there is nothing previous to it
        {
            cout << "Previous Value = " << (--iter)->second << endl;    //Need to pre-decrement the iterator to get the previous value
            ++iter;    //Need to increment the iterator, since it was decremented above (post or pre increment doesn't matter here, since no operation is done on the iterator)
        }
    }
    
  24. Map: Remove an element
    The standard associative-container erase idiom:
    for(std::map::iterator iter = myMap.begin(); iter != myMap.end(); /* no iterator increment */)
    {
        if(must_delete)
        {
            myMap.erase(iter++);
        }
        else
        {
            ++iter;
        }
    }
    
  25. Map: Find and Replace an element
    std::map myMap;
    myMap.insert(std::make_pair('c', 0));  // c is for cookie
    
    std::map::iterator iter = myMap.find('c'); 
    
    if(iter != myMap.end())
    {
        iter->second = 42;
    }
    
  26. Map: Check if an element being inserted is already present
    Element keys in a map are unique. For a similar container allowing for duplicate elements, use multimap.
    std::map myMap;
    myMap.insert(std::make_pair(11, "Hello"));
    myMap.insert(std::make_pair(22, "Jello"));
    
    if(!(myMap.insert(std::make_pair(11, "Fello"))).second)
    {
        cout << "Key is already present in Map and will not be inserted" << endl;
    }
    
  27. Class: Initialization List
    A.hpp
    public:
        A(int row, int col): m_row(row), m_col(col) {};
    
    OR
    Combination of header and implementation file
    A.hpp
    public:
        A(int row, int col);
    
    A.cpp
    A::A(int row, int col) : m_row(row), m_col(col) 
    {
    }
    
  28. Class: Best Get and Set methods
    const std::vector& MyClass::GetMyVector() const
    {
        return  m_myVector;
    }
    
    void MyClass::SetMyVector(const std::vector& vector)
    {
        m_myVector = vector;
    }
    
  29. Class: Singleton Design Pattern
    class MySingletonClass
    {
        public:
            static MySingletonClass& getInstance()
            {
                static MySingletonClass    instance;      // Guaranteed to be destroyed.
                                                          // Instantiated on first use.
                return instance;
            }
        private:
            MySingletonClass() {};                        // Constructor? (the {} brackets) are needed here.
                                                          // Don't forget to declare these two. You want to make sure they
                                                          // are inaccessible otherwise you may accidently get copies of
                                                          // your singleton appearing.
            MySingletonClass(MySingletonClass const&);    // Copy Constructor. Don't Implement
            void operator=(MySingletonClass const&);      // Assignment (=) Operator. Don't implement
    };
    
  30. Class: When do you need to make your destructor virtual
    • if someone will derive from your class,
    • and if someone will say new Derived, where Derived is derived from your class,
    • and if someone will say delete p, where the actual object's type is Derived but the pointer p's type is your class.
    • or
    • No intention to derive classes from it
    • No instantiation on the heap
    • No intention to store in a pointer of a superclass
  31. Class: Overloading Comparison Operator
    std::find require the value to be equality comparable, and the compiler does not automatically define/generate you a default operator==. So if you don't write one yourself, objects of your class can't be compared for equality.
    std::find is a function template and it uses argument-dependent lookup (ADL) to find the right operator== to use.
    So comparison operator== needs to be overloaded with some comparison logic.
    Overloaded operator should be a public method.
    Built-in data types which includes pointers, don't use overloaded operator==
    So, even if comparison operator is overloaded, if pointers are used in std::find, the operator definition method won't be called.

    std::find doesn't take compare function.
    std::find_if doesn't take value.
    Alternatively, you can use std::find_if and supply a functor predicate.
    The compare function takes only one argument.

    std::find(strings.begin(), strings.end(), "hello");
    std::find_if(strings.begin(), strings.end(), compare);
    std::find_if(strings.begin(), strings.end(), compare("hello"));

No comments:

Post a Comment