Tag Archives: Boost

Using boost::enable_shared_from_this

The boost::enable_shared_from_this class is designed to allow a method of an object that has already been instantiated wrapped in a shared_ptr to return this as a shared_ptr correctly. This is necessary because simply returning a shared_ptr(this) will create another shared_ptr with its own reference count, which would conflict with the exisiting one and subvert reference counting.

For example, consider the class outline below which is fairly typical of a heap-allocated, non-copyable class using shared_ptr:

#include <boost/shared_ptr.hpp>
#include <boost/core/noncopyable.hpp>

class X : private boost::noncopyable
{
public:
    typedef boost::shared_ptr<X> Ptr;
    typedef boost::shared_ptr<const X> ConstPtr;
private:
    X()
    {
    }
public:
    static Ptr New()
    {
        return Ptr(new X());
    }
};

Now imagine we add the following method, which returns this wrapped in a shared_ptr, perhaps to facilitate method chaining:

    Ptr F()
    {
        // Do something...
        return Ptr(this);
    }

The problem now is that the Ptr returned by F() is in addition to the Ptr already wrapping this instance, so although it refers to the same underlying raw pointer, it has its own reference count, as the following program demonstrates:

int main()
{
    X::Ptr x1 = X::New();
    X::Ptr x2 = x1->F();
    std::cout << std::boolalpha << "x1 == x2?: "<< (x1 == x2) << "\n";
    std::cout << std::boolalpha << "!(x1 < x2 || x < x2)?: " <<  (!(x1 < x2 || x2 < x1)) << "\n";
}

This outputs:

x1 == x2?: true
!(x1 < x2 || x < x2)?: false

Operator== is showing that the two variables are holding the same raw pointer, but operator<, which is overloaded to show whether two pointers actually share ownership, shows that they do not.

When the first pointer goes out of scope, it will decrement its reference count to 0 and delete the object. When the second one too goes out of scope, it will attempt to do the same, with undefined results.

The solution is to use boost::enable_shared_from_this. This just involves:

  1. Include boost/enable_shared_from_this.hpp
  2. Derive your class publicly from boost_enable_shared_from_this, which takes the class as a template parameter (the Curiously Recurring Template Pattern)
  3. Whenever you want to return this wrapped in a shared_ptr, use the inherited shared_from_this() method.

Here is our example class with those changes added:

#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/core/noncopyable.hpp>

class X : public boost::enable_shared_from_this<X>,
   private boost::noncopyable
{
public:
    typedef boost::shared_ptr<X> Ptr;
    typedef boost::shared_ptr<const X> ConstPtr;
private:
    X()
    {
    }
public:
    static Ptr New()
    {
        return Ptr(new X());
    }
    Ptr F()
    {
        return shared_from_this();
    }
};

This is the result of running the test program now:

x1 == x2?: true
!(x1 < x2 || x < x2)?: true

So now the ownership of the raw pointer is correctly shared.

References:
noncopyable
shared_ptr class template
enable_shared_from_this

Populate a vector with literal values

Method 1: Use an array and the range constructor

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

int main()
{
    typedef std::vector<int> intvec;

    int arr[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30};
    const size_t n = sizeof(arr) / sizeof(int);
    intvec vec1(arr, arr + n);
    
    std::copy(vec1.begin(), vec1.end(), std::ostream_iterator<int>(std::cout, " "));
}

Method 2: Use boost::assign::list_of

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <boost/assign/list_of.hpp>
#include <boost/range/algorithm/copy.hpp>

int main()
{
    typedef std::vector<int> intvec;

    int arr[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30};
    const size_t n = sizeof(arr) / sizeof(unsigned int);
    
    intvec vec2 = boost::assign::list_of(31)(28)(31)(30)(31)(30)(31)(31)(30)(31)(30);
    
    boost::copy(vec2, std::ostream_iterator<int>(std::cout, " "));
}

Method 3: Use boost::assign

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <boost/assign/std/vector.hpp>
#include <boost/range/algorithm/copy.hpp>
using namespace boost::assign; // bring 'operator+=()' into scope

int main()
{
    typedef std::vector<int> intvec;

    intvec vec3;
    vec3 += 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30;
    
    boost::copy(vec3, std::ostream_iterator<int>(std::cout, " "));
}

Method 4: Use a C++11 initializer

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

int main()
{
    typedef std::vector<int> intvec;

    intvec vec4 = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30};
    
    std::copy(vec4.begin(), vec4.end(), std::ostream_iterator<int>(std::cout, " "));
}

Related

How to replace all occurrences of a character in a std::string

This can be done using the standard library or Boost. The advantage of using Boost is that you get Boost ranges, which mean that you don’t need to specify the beginning and end of the string.

With both libraries, the replacement can be made on the original string or a copy.

  1. Use std::replace()
  2. Use std::replace_copy
  3. Use boost_replace_all
  4. Use boost_replace_all_copy

Method 1: Use std::replace()

#include <iostream>
#include <string>
#include <algorithm>

int main()
{
    std::string str("Quick+brown+fox");
    std::replace(str.begin(), str.end(), '+', ' ');
    std::cout << str << "\n";
}

Method 2: Use std::replace_copy

#include <iostream>
#include <string>
#include <algorithm>

int main()
{
    std::string str1("Quick+brown+fox");
    std::string str2(str1.size(), '\0');
    std::replace_copy(str1.begin(), str1.end(), str2.begin(), '+', ' ');
    std::cout << str2 << "\n";
}

Method 3: Use boost_replace_all

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

int main()
{
    std::string str("Quick+brown+fox");
    boost::replace_all(str, "+", " ");
    std::cout << str << "\n";
}

Method 4: Use boost_replace_all_copy

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

int main()
{
    std::string str1("Quick+brown+fox");
    std::string str2 =  boost::replace_all_copy(str1, "+", " ");
    std::cout << str2 << "\n";
}

References:
Function template replace_all
Function replace_all_copy

Related

How to list the Files in a Directory in C++

Introduction

Imagine that we want to populate a vector with the names of the files in a directory with a read_directory() function like this:

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

typedef std::vector<std::string> stringvec;

int main()
{
    stringvec v;
    read_directory(".", v);
    std::copy(v.begin(), v.end(),
         std::ostream_iterator<std::string>(std::cout, "\n"));
}

There are 4 methods we can use:

  1. Use boost::filesystem::directory_iterator
  2. Use std::filesystem::directory_iterator (C++17)
  3. Use opendir()/readdir()/closedir() (POSIX)
  4. Use FindFirstFile()/FindNextFile()/FindClose() (Windows)

Method 1: Use boost::filesystem

#include <boost/filesystem.hpp>

struct path_leaf_string
{
    std::string operator()(const boost::filesystem::directory_entry& entry) const
    {
        return entry.path().leaf().string();
    }
};

void read_directory(const std::string& name, stringvec& v)
{
    boost::filesystem::path p(name);
    boost::filesystem::directory_iterator start(p);
    boost::filesystem::directory_iterator end;
    std::transform(start, end, std::back_inserter(v), path_leaf_string());
}

Reference: Boost Filesystem Library Version 3

Method 2: Use std::filesystem (C++17)

#include <filesystem>

struct path_leaf_string
{
    std::string operator()(const std::filesystem::directory_entry& entry) const
    {
        return entry.path().leaf().string();
    }
};

void read_directory(const std::string& name, stringvec& v)
{
    std::filesystem::path p(name);
    std::filesystem::directory_iterator start(p);
    std::filesystem::directory_iterator end;
    std::transform(start, end, std::back_inserter(v), path_leaf_string());
}

Method 3: Use opendir()/readdir()/closedir() (POSIX)

#include <sys/types.h>
#include <dirent.h>

void read_directory(const std::string& name, stringvec& v)
{
    DIR* dirp = opendir(name.c_str());
    struct dirent * dp;
    while ((dp = readdir(dirp)) != NULL) {
        v.push_back(dp->d_name);
    }
    closedir(dirp);
}

Reference: readdir – The Open Group

Method 4: Use FindFirstFile()/FindNextFile()/FindClose() (Windows)

#include <windows.h>

void read_directory(const std::string& name, stringvec& v)
{
    std::string pattern(name);
    pattern.append("\\*");
    WIN32_FIND_DATA data;
    HANDLE hFind;
    if ((hFind = FindFirstFile(pattern.c_str(), &data)) != INVALID_HANDLE_VALUE) {
        do {
            v.push_back(data.cFileName);
        } while (FindNextFile(hFind, &data) != 0);
        FindClose(hFind);
    }
}

Reference: FindFirstFile function

Related

How to read a file into a string in C++

Looping over a container in C++

It’s best to use an algorithm when processing a container, or the contents of any pair of iterators, in C++, but it’s good to know how to iterate when you have to.

Here’s the vector we’re going to use:

#include <iostream>
#include <vector>
#include <algorithm>

typedef std::vector<int> intvec;

int main()
{  
    intvec v(10);
    std::iota(v.begin(), v.end(), 0);
    iterate(v);
}

Method 1: Use iterators

This is the most familiar interface.

void iterate(const intvec& v)
{
    for (intvec::const_iterator it = v.begin(); it != v.end(); ++it) {
        // Do something with *it
    }
}

Method 2: Use indices

Note that only random access containers like vector and deque support indexed access.

void iterate(const intvec& v)
{
    for (intvec::size_type i = 0; i < v.size(); ++i) {
        // Do something with v[i]
    }
}

Method 3: Use Boost.Foreach

This was the most elegant method until C++11.

#include <boost/foreach.hpp>

void iterate(const intvec& v)
{
    BOOST_FOREACH(intvec::value_type el, v) {
        // Do something with el
    }
}

Reference: Boost.Foreach

Method 4: Use a range-based for loop

This is now the recommended method.

void iterate(const intvec& v)
{
    for (const auto& el: v) {
        // Do something with el
    }
}

How to do case-insensitive string comparison in C++

Methods

  1. Use std::equal and std::toupper
  2. Use boost::iequals

1. Use std::equal and std::toupper

#include <string>
#include <algorithm>
#include <cstring>

struct iequal
{
    bool operator()(int c1, int c2) const
    {
        return std::toupper(c1) == std::toupper(c2);
    }
};

bool iequals(const std::string& str1, const std::string& str2)
{
    return std::equal(str1.begin(), str1.end(), str2.begin(), iequal());
}

2. Use boost::iequals

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

bool same = boost::iequals(str1, str2);

Reference: Function template iequals

Related

How to concatenate a string and an int in C++

Methods

  • Use std::stringstream
  • Use boost::lexical_cast()
  • Use boost::format()
  • Use std::to_string() (C++11)

Method 1. Use std::stringstream

#include <sstream>

std::stringstream ss;
ss << name << age;
result = ss.str();

Method 2. Use boost::lexical_cast()

#include <boost/lexical_cast.hpp>

result = name + boost::lexical_cast<std::string>(age);

Reference: Boost.Lexical_Cast

Method 3. Use boost::format()

#include <boost/format.hpp>

result =  boost::str(boost::format("%s%d") % name % age);

Reference: Boost Format library

Method 4. Use std::to_string() (C++11)

result = name + std::to_string(age);

Method 5. Use folly::toAppend()

#include <folly/Conv.h>

result =  name;
folly::toAppend(age, &result);

Reference: folly/Conv.h

Related

How to convert a string to lower or upper case in C++

1. Use std::transform and tolower or toupper

    #include <algorithm>
    #include <string>
    #include <cctype> 

    std::string& to_lower(std::string& str)
    {
        std::transform(str.begin(), str.end(), str.begin(), static_cast<int(*)(int)>(std::tolower));
        return str;
    }

    std::string& to_upper(std::string& str)
    {
        std::transform(str.begin(), str.end(), str.begin(), static_cast<int(*)(int)>(std::toupper));
        return str;
    }

    std::string str = "Chorlton-cum-Hardy"; 
    to_lower(str);
    to_upper(str);

2. Use boost::algorithm::to_lower or boost::algorithm::to_upper

    #include <boost/algorithm/string.hpp>    

    std::string str = "Adwick-le-Street";
    boost::algorithm::to_lower(str);
    boost::algorithm::to_upper(str);

References:
Function template to_lower
Function template to_upper

Related

How to convert an int to a std::string in C++

Methods

  1. Use std::stringstream
  2. Use boost::lexical_cast
  3. Use folly::to()
  4. Use std::to_string (C++11)

Method 1: Use std::stringstream

#include <sstream>

template <typename T>
std::string to_string(const T& thing)
{
    std::stringstream ss;
    ss << thing;
    return ss.str();
}

template <>
std::string to_string<std::string>(const std::string& s)
{
    return s;
}

std::cout << ::to_string(n) << "\n";

Method 2: Use boost::lexical_cast

#include <boost/lexical_cast.hpp>
std::cout << boost::lexical_cast<std::string>(n) << "\n";

Reference: Boost.Lexical_Cast

Method 3: Use folly::to()

#include <folly/Conv.h>
std::cout << folly::to<std::string>(n) << "\n";

Reference: folly/Conv.h

Method 4: Use std::to_string (C++11)

std::cout << std::to_string(n) << "\n";

Related

Smart pointers

The standard library and Boost smart pointers fall into two types: scoped pointers and reference counted pointers.

Scoped pointers

boost::scoped_ptr and std::unique_ptr
The object is destroyed when the pointer instance goes out of scope.
They cannot be copied (although you can pass them by reference)
The lifetime of the object is tied either to:

  • The current scope
  • The lifetime of the containing object

The second of these makes them suitable for storage in containers.
The old std::auto_ptr is like a scoped pointer, except that it can be copied, which transfers ownership.
It is deprecated in the newer standards and should not be used.

Reference counted pointers

boost::shared_ptr and std::shared_ptr
Allows the pointer to be copied.
Useful when the lifetime of the object is more complicated.
Potential problems:

  • Creating them on the heap
  • Passing them by reference
  • Creating circular references

The last point is mitigated by boost::weak_ptr and std::weak_ptr, which define a weak (i.e., uncounted) reference to a shared_ptr.