Casting operators in C++

  • static_cast<>
  • const_cast<>
  • dynamic_cast<>
  • reinterpret_cast<>
  • C-style casts

static_cast<>
Is for widening numeric conversions (e.g., int to float), converting between pointer types and void*.
Can also be used to call explicit (or implicit) conversion functions.
Can cast around the hierarchy but it isn’t checked.

const_cast<>
Add or remove const to a variable.
Not so important because of mutable.
Can be used to call const-overloaded member functions.
Can also add or remove volatile

dynamic_cast<>
For casting around hierarchies.
Will return nullptr on failure for a pointer, or throw std::bad_cast for references.
Can cast sideways and up other hierarchies
Doesn’t work if you have a diamond and haven’t used virtual inheritance
Only works for public inheritance

reinterpret_cast<>
Will convert anything into anything.
Use to cast a pointer to or from an opaque type, or to cast a blob of memory to a POD type
Is reversible unless you cast to a type with less storage space

C-style casts
T(object) or (T)object
This is the same thing as a "function-style cast"
Perform the new casts in order:

  1. const_cast
  2. static_cast
  3. static_cast then const_cast
  4. reinterpret_cast
  5. reinterpret_cast then const_cast

Note that dynamic_cast is not in this list – you can cast around the hierarchy with C-style casts, but it isn’t checked

Differences Between pointers and references in C++

  1. A pointer can be declared uninitialized, but a reference must be declared referring to something
  2. A pointer can be reassigned, but a reference cannot be reassigned – assigning to it changes the referent
  3. Pointers can be NULL, but there is no equivalent for references – they always need to refer to a valid object
  4. You can take the address of a pointer, but you can’t take the address of a reference (you’ll get the address of the referent)
  5. You can make a pointer to a pointer, or a reference to a pointer, but you can’t make a reference to a reference
  6. You can do arithmetic with pointers, but you can’t do arithmetic with references (it would attempt to do arithmetic with the referent)
  7. You de-reference pointers, but you don’t de-reference references (they are automatically de-referenced)
  8. When you call a function that takes a pointer, you can always see at the call site that the argument is a pointer (because it’s declared as a pointer variable, or you take the address of it), but the creation of a reference by function call isn’t explicit at the call site

The yield keyword in Python

To understand how yield works, you need to understand iterables, iterators, and generators

Iterables

An iterable is an object capable of returning its members one at a time. Iterables include:
All sequence types, such as:

  • list
  • str
  • tuple

Some none-sequence types, such as:

  • dict
  • file objects
  • any objects of user-defined classes with an __iter__() method or with a __getitem__() method that implements Sequence
    semantics (see below)

Iterables can be used in a for loop and in many other places where a sequence is needed:

  • zip()
  • map()

When an iterable object is passed to the built-in function iter(), it returns an iterator for the object.
The iterator is good for one pass over the set of values
It is usually not necessary to call iter() directly, as the for statement does this for you, creating a temporary unnamed
variable to hold the iterator for the duration of the loop.

User-defined iterables need to define one of __iter__() or __getitem__().

__iter__()
Called when an iterator is required for a container.
Iterator objects also need to implement this method; they are required to return themselves.

__getitem__()
Called to implement self[key].
For sequence types, the accepted keys should be integers or slice objects.
The interpretation of negative slices is the responsibility of the __getitem__() method.
If key is of the wrong type, a TypeError may be raised.
If the key is of a value outside the set of indexes for the sequence, an IndexError should be raised.
For mapping types, if key is missing, a KeyError should be raised.

Iterators

An iterator is an object representing a stream of data.
Calls to the object’s __next__() method (or passing it to the built-in function next()) return successive items in the
stream.
When no more data are available, a StopIteration exception is raised.
The iterator is then exhausted, and any subsequent calls to __next__() method will raise a StopIteration again.
Iterators are required to have an __iter__() method so every iterator is also iterable and may be used in most places where
other iterables are accepted.

Generators

The word generator refers to two things: a generator function and a generator iterator.

Generator function
A generator function is like a normal function except that it contains one or more yield expressions.
When a generator function is called, its code is not executed, and instead it returns a generator iterator.

Generator iterator
This is an iterator that controls the execution of the generator function in response to calls to the next() function.
Each yield in the associated generator function causes execution to be temporarily suspended. When the iterator resumes, execution continues from where it left off.

How to split a string in C++

Java has String.split(), Python has string.split(), Perl has split. There is no simple string-splitting method in C++, but there are plenty of ways of doing it. Here are some methods:

  1. Put it in a stringstream and extract the tokens
  2. Put it in a stringstream and use getline() with a delimiter
  3. Use string::find progressively
  4. Use string::find_first_of progressively with a number of delimiters
  5. Use boost::split()
  6. Use boost::split_iterator
  7. Use boost::tokenizer
  8. Use boost::sregex_token_iterator
  9. Use pystring::split
  10. Use my C split function

1. Put it in a stringstream and extract the tokens

#include <string>
#include <sstream>
#include <algorithm>
#include <iterator>

template <class Container>
void split1(const std::string& str, Container& cont)
{
    std::istringstream iss(str);
    std::copy(std::istream_iterator<std::string>(iss),
         std::istream_iterator<std::string>(),
         std::back_inserter(cont));
}

2. Put it in a stringstream and use getline() with a delimiter

#include <string>
#include <sstream>
#include <algorithm>
#include <iterator>

template <class Container>
void split2(const std::string& str, Container& cont, char delim = ' ')
{
    std::stringstream ss(str);
    std::string token;
    while (std::getline(ss, token, delim)) {
        cont.push_back(token);
    }
}

3. Use string::find progressively

#include <string>
#include <algorithm>
#include <iterator>

template <class Container>
void split3(const std::string& str, Container& cont,
              char delim = ' ')
{
    std::size_t current, previous = 0;
    current = str.find(delim);
    while (current != std::string::npos) {
        cont.push_back(str.substr(previous, current - previous));
        previous = current + 1;
        current = str.find(delim, previous);
    }
    cont.push_back(str.substr(previous, current - previous));
}

4. Use string::find_first_of progressively with a number of delimiters

#include <string>
#include <algorithm>
#include <iterator>

template <class Container>
void split4(const std::string& str, Container& cont,
              const std::string& delims = " ")
{
    std::size_t current, previous = 0;
    current = str.find_first_of(delims);
    while (current != std::string::npos) {
        cont.push_back(str.substr(previous, current - previous));
        previous = current + 1;
        current = str.find_first_of(delims, previous);
    }
    cont.push_back(str.substr(previous, current - previous));
}

5. Use boost::split()

#include <string>
#include <boost/algorithm/string.hpp>

template <class Container>
void split5(const std::string& str, Container& cont,
              const std::string& delims = " ")
{
    boost::split(cont, str, boost::is_any_of(delims));
}

Reference: Function template split

6. Use boost::split_iterator

#include <string>
#include <boost/algorithm/string.hpp>

template <class Container>
void split6(const std::string& str, Container& cont,
              char delim = ' ')
{
    typedef boost::split_iterator<std::string::const_iterator> spliterator;
    std::string sdelim(1, delim);
    for (spliterator it = boost::make_split_iterator(str, 
               boost::first_finder(sdelim, boost::is_equal()));
               it != spliterator(); ++it) {
        cont.push_back(boost::copy_range<std::string>(*it));
    }
}

Reference: Function template make_split_iterator

7. Use Use boost::tokenizer

#include <string>
#include <algorithm>
#include <boost/tokenizer.hpp>

template <class Container>
void split7(const std::string& str, Container& cont,
              const std::string& delims = " ")
{
    typedef boost::char_separator<char> separator;
    boost::tokenizer<separator> tokens(str, separator(delims.c_str()));
    std::copy(tokens.begin(), tokens.end(), std::back_inserter(cont)); 
}

Reference: Tokenizer Class

8. Use boost::sregex_token_iterator

#include <string>
#include <algorithm>
#include <boost/regex.hpp>

template <class Container>
void split8(const std::string& str, Container& cont,
              const std::string delim = "\\s+")
{
    boost::regex re(delim);
    std::copy(boost::sregex_token_iterator(str.begin(), str.end(), re, -1),
            boost::sregex_token_iterator(), 
            std::back_inserter(cont)); 
}

Reference: regex_token_iterator

9. Use pystring::split()

#include <pystring.h>

template <class Container>
void split9(const std::string& str, Container& cont,
              const std::string delim = " ")
{
    std::vector<std::string> vec;
    pystring::split(str, vec, delim);
    std::copy(vec.begin(), vec.end(), std::back_inserter(cont));
}

Reference: pystring/pystring.h

10. Use my C split function

template <class Container>
void add_to_container(const char *str, size_t len, void *data)
{
    Container *cont = static_cast<Container*>(data);
    cont->push_back(std::string(str, len));
}

template <class Container>
void split10(const std::string& str, Container& cont, char delim = ' ')
{
    split(str.c_str(), delim, static_cast<split_fn>(add_to_container<Container>), &cont);
}

Reference: Split a string in C

An example program

#include <iostream>
#include <string>
#include <algorithm>
#include <iterator>
#include <vector>

int main()
{
    char str[] = "The quick brown fox jumps over the lazy dog";
    std::vector<std::string> words;
    split1(str, words);
    std::copy(words.begin(), words.end(),
         std::ostream_iterator<std::string>(std::cout, "\n"));
}
The
quick
brown
fox
jumps
over
the
lazy
dog

Related