c++11

Playing with c++11 and posix regular expression libraries

July 24, 2016 C/C++ development and debugging. , , , , , , , , ,

I was curious how the c++11 std::regex interface compared to the C posix regular expression library. The c++11 interfaces are almost as easy to use as perl. Suppose we have some space separated fields that we wish to manipulate, showing an order switch and the original:

my @strings = ( "hi bye", "hello world", "why now", "one two" ) ;

foreach ( @strings )
{
   s/(\S+)\s+(\S+)/'$&' -> '$2 $1'/ ;

   print "$_\n" ;
}

The C++ equivalent is

   const char * strings[] { "hi bye", "hello world", "why now", "one two" } ;

   std::regex re( R"((\S+)\s+(\S+))" ) ;

   for ( auto s : strings )
   {
      std::cout << regex_replace( s, re, "'$&' -> '$2 $1'\n" )  ;
   }

We have one additional step with the C++ code, compiling the regular expression. Precompilation of perl regular expressions is also possible, but that is usually just as performance optimization.

The posix equivalent requires precompilation too

void posixre_error( regex_t * pRe, int rc )
{
   char buf[ 128 ] ;

   regerror( rc, pRe, buf, sizeof(buf) ) ;

   fprintf( stderr, "regerror: %s\n", buf ) ;
   exit( 1 ) ;
}

void posixre_compile( regex_t * pRe, const char * expression )
{
   int rc = regcomp( pRe, expression, REG_EXTENDED ) ;
   if ( rc )
   { 
      posixre_error( pRe, rc ) ;
   }
}

but the transform requires more work:

void posixre_transform( regex_t * pRe, const char * input )
{
   constexpr size_t N{3} ;
   regmatch_t m[N] {} ;

   int rc = regexec( pRe, input, N, m, 0 ) ;

   if ( rc && (rc != REG_NOMATCH) )
   {
      posixre_error( pRe, rc ) ;
   }

   if ( !rc )
   { 
      printf( "'%s' -> ", input ) ;
      int len ;
      len = m[2].rm_eo - m[2].rm_so ; printf( "'%.*s ", len, &input[ m[2].rm_so ] ) ;
      len = m[1].rm_eo - m[1].rm_so ; printf( "%.*s'\n", len, &input[ m[1].rm_so ] ) ;
   }
}

To get at the capture expressions we have to pass an array of regmatch_t’s. The first element of that array is the entire match expression, and then we get the captures after that. The awkward thing to deal with is that the regmatch_t is a structure containing the start end end offset within the string.

If we want more granular info from the c++ matcher, it can also provide an array of capture info. We can also get info about whether or not the match worked, something we can do in perl easily

my @strings = ( "hi bye", "helloworld", "why now", "onetwo" ) ;

foreach ( @strings )
{
   if ( s/(\S+)\s+(\S+)/$2 $1/ )
   {
      print "$_\n" ;
   }
}  

This only prints the transformed line if there was a match success. To do this in C++ we can use regex_match

const char * pattern = R"((\S+)\s+(\S+))" ;

std::regex re( pattern ) ;

for ( auto s : strings )
{ 
   std::cmatch m ;

   if ( regex_match( s, m, re ) )
   { 
      std::cout << m[2] << ' ' << m[1] << '\n' ;
   }
}

Note that we don’t have to mess around with offsets as was required with the Posix C interface, and also don’t have to worry about the size of the capture match array, since that is handled under the covers. It’s not too hard to do wrap the posix C APIs in a C++ wrapper that makes it about as easy to use as the C++ regex code, but unless you are constrained to using pre-C++11 code and can also live with a Unix only restriction. There are also portability issues with the posix APIs. For example, the perl-style regular expressions like:

   R"((\S+)(\s+)(\S+))" ) ;

work fine with the Linux regex API, but that appears to be an exception. To make code using that regex work on Mac, I had to use strict posix syntax

   R"(([^[:space:]]+)([[:space:]]+)([^[:space:]]+))"

Actually using the Posix C interface, with a portability constraint that avoids the Linux regex extensions, would be horrendous.

some c++11 standard library notes

July 9, 2016 C/C++ development and debugging. , , , , ,

Some notes on Chapter 31, 32 (standard library, STL) of Stroustrup’s “The C++ Programming Language, 4th edition”.

Emplace

I’d never heard the word emplace before, but it turns out that it isn’t a word made up for c++, but is also a dictionary word, meaning to “put into place or position”.

c++11 defines some emplace functions. Here’s an example for vector

#include <vector>
#include <iostream>

int main()
{
   using pair = std::pair<int, int> ;
   using vector = std::vector< pair > ;

   vector v ;

   pair p{ 1, 2 } ;
   v.push_back( p ) ;
   v.push_back( {2, 3} ) ;
   v.emplace_back( 3, 4 ) ;

   for ( auto e : v )
   {
      std::cout << e.first << ", " << e.second << '\n' ;
   }

   return 0 ;
}

The emplace_back is like the push_back function, but does not require that a constructed object be created first, either explicitly as in the object p above, or implictly as done with the {2, 3} pair initializer list.

multimap

I’d written some perl code the other day when I wanted a hash that had multiple entries per key. Since my hashed elememts were simple, I just strung them together as comma separated entries (I could have also used a hash of array references). It looks like c++11 builds exactly the construct that I wanted into STL, and has both a multimap and unordered_multimap. Here’s an example of the latter

#include <unordered_map>
#include <string>
#include <iostream>

int main()
{
   std::unordered_multimap< int, std::string > m ;

   m.emplace( 3, "hi" ) ;
   m.emplace( 3, "bye" ) ;
   m.emplace( 4, "wow" ) ;

   for ( auto & v : m )
   {
      std::cout << v.first << ": " << v.second << '\n' ;
   }
  
   for ( auto f{ m.find(3) } ; f != m.end() ; ++f )
   {
      std::cout << "find: " << f->first << ": " << f->second << '\n' ;
   }
   
   return 0 ;
} 

Running this gives me

$ ./a.out 
4: wow
3: hi
3: bye
find: 3: hi
find: 3: bye

Observe how nice auto is here. I don’t have to care what the typename for the unordered_multimap find result is. According to gdb that type is:

(gdb) whatis f
type = std::__1::__hash_map_iterator<std::__1::__hash_iterator<std::__1::__hash_node<std::__1::__hash_value_type<int, std::__1::basic_string<char> >, void*>*> >

Yikes!

STL

The STL chapter outlines lots of different algorithms. One new powerful feature in c++11 is that the Lambdas can be used instead of predicate function objects, which is so much cleaner. I used that capability in a scientific computing programming assignment earlier this year with partial_sort.

The find_if_not algorthim caught my eye, because I just manually coded exactly that sort of loop translating intel assembly that used ‘REPL SCASB’ instructions, and that code was precisely of this find_if_not form. The c++ equivalent of the assembly was roughly of the following form:

int scan3( const std::string & s, char v )
{
   auto p = s.begin() ;
   for ( ; p != s.end() ; p++ )
   {
      if ( *p != v )
      {
         break ; 
      }
   }

   if ( p == s.end() )
   {
      return 0 ;
   }
   else
   {
      std::cout << "diff: " << p - s.begin() << '\n' ;

      return ( v > *p ) ? 1 : -1 ;
   }

Range for can also be used for this loop, but it is only slightly clearer:

int scan2( const std::string & s, char v )
{
   auto p = s.begin() ;
   for ( auto c : s )
   {
      if ( c != v )
      {
         break ;
      }

      p++ ;
   }

   if ( p == s.end() )
   { 
      return 0 ;
   }
   else
   { 
      std::cout << "diff: " << p - s.begin() << '\n' ;

      return ( v > *p ) ? 1 : -1 ;
   }
}

An STL version of this loop that uses a lambda predicate is

int scan( const std::string & s, char v )
{
   auto i = find_if_not( s.begin(),
                         s.end(),
                         [ v ]( char c ){ return c == v ; }
                       ) ;

   if ( i == s.end() )
   { 
      return 0 ;
   }
   else
   { 
      std::cout << "diff: " << i - s.begin() << '\n' ;

      return ( v > *i ) ? 1 : -1 ;
   }
}

I don’t really think that this is any more clear than explicit for loop versions. All give the same results when tried:

int main()
{
   std::vector< std::function< int( const std::string &, char ) > > v { scan, scan2, scan3 } ;

   for ( auto f : v )
   { 
      int r0 = f( "nnnnn", 'n' ) ;
      int rp = f( "nnnnnmmm", 'n' ) ;
      int rn = f( "nnnnnpnn", 'n' ) ;

      std::cout << r0 << '\n' ;
      std::cout << rp << '\n' ;
      std::cout << rn << '\n' ;
   }

   return 0 ;
}

The compiler does almost the same for all three implementations. With the cout’s removed, and compiling with optimization, the respective instruction counts are:

(gdb) p 0xee3-0xe70
$1 = 115
(gdb) p 0xf4c-0xef0
$2 = 92
(gdb) p 0xfc3-0xf50
$3 = 115

The listings for the STL and the C style for loop are almost the same. The Apple xcode 7 compiler seems to produce slightly more compact code for the range-for version of this function for reasons that are not obvious to me.

c++11 virtual function language changes.

July 1, 2016 C/C++ development and debugging. , , , , , , ,

Chapter 20 of Stroustrup’s book covers a few more new (to me) c++11 features:

  1. override
  2. final
  3. use of using statements for access control.
  4. pointer to member (for data and member functions)

override

The override keyword is really just to make it clear when you are providing a virtual function override.  Because the use of virtual at an override point is redundant, people have used that to explicitly show that the intent is to show the function overrides a base class function. However, if the have the interface erroneously different in the second specification, the use of virtual there means that you are defining a new virtual function.  Here’s a made up example, where the integer type of a virtual function was changed “accidentally” when “overriding” a base class virtual function:

#include <stdio.h>

struct x
{
   virtual void foo( int v ) ;
} ;

struct y : public x
{
   virtual void foo( long v ) ;
} ;

void x::foo( int v ) { printf( "x::foo:%d\n", v ) ; }
void y::foo( long v ) { printf( "y::foo:%ld\n", v ) ; }

Now in c++11 you can be explicit that you intention is to override a base class virtual. Replace the use of the redundant virtual with the override keyword, and the compiler can now tell you if you get things mixed up:

struct x
{
   virtual void foo( int v ) ;
} ;

struct y : public x
{
   void foo( long v ) override ;
} ;

void x::foo( int v )
{
   printf( "x::foo:%d\n", v ) ;
}

void y::foo( long v )
{
   printf( "y::foo:%ld\n", v ) ;
}

This gives a nice compiler message informing you about the error:

$ c++ -std=c++11 -O2 -MMD   -c -o d.o d.cc
d.cc:10:23: error: non-virtual member function marked 'override' hides virtual member function
   void foo( long v ) override ;
                      ^
d.cc:5:17: note: hidden overloaded virtual function 'x::foo' declared here: type mismatch at 1st parameter ('int' vs 'long')
   virtual void foo( int v ) ;
                ^

final

This is a second virtual function modifier designed to cut the performance cost of using virtual functions in some situations. My experimentation with this feature shows the compilers still have more work to do optimizing away the vtable calls. I introduced a square-matrix class that had a single range virtual range checking function:

   void throwRangeError( const indexType i, const indexType j ) const
   { 
      throw rangeError{ i, j, size } ;
   }

   /**
      Introduce a virtual function that allows user selection of optional range error checking.
    */
   virtual void handleRangeError( const indexType i, const indexType j ) const
   { 
      throwRangeError( i, j ) ;
   }

   bool areIndexesOutOfRange( const indexType i, const indexType j ) const
   { 
      if ( (0 == i) or (0 == j) or (i > size) or (j > size) )
      { 
         return true ;
      }

      return false ;
   }

My intent was that a derived class could provide a no-op specialization of handleRangeError:

/**
   Explicitly unchecked matrix element access
 */
class uncheckedMatrix : public matrix
{
public:
   // inherit constructors:
   using matrix::matrix ;

   void handleRangeError( const indexType i, const indexType j ) const final
   {
   }
} ;

This derived class no longer has any virtual functions. Also note that it uses ‘using’ statements to explicitly inherit the base class constructors, which is not a default action (and recommended by Stroustrup only for classes like this that do not add any data members).

The compiler didn’t do too well with this specialization, as calls to the element access operator still took a vtable hit. Here’s some code that when passed a 3×3 matrix object includes out of range accesses:

void outofbounds( const matrix & m, const char * s )
{
   printf( "%s: %g\n", s, m(4,2) ) ;
}

void outofbounds( const checkedMatrix & m, const char * s )
{
   printf( "%s: %g\n", s, m(4,2) ) ;
}

void outofbounds( const uncheckedMatrix & m, const char * s ) noexcept
{
   printf( "%s: %g\n", s, m(4,2) ) ;
}

Here’s the code for the first (base class) matrix class that has virtual functions, but no final overrides:

0000000000000000 <outofbounds(matrix const&, char const*)>:
   0: push   %rbp
   1: mov    %rsp,%rbp
   4: push   %r14
   6: push   %rbx
   7: mov    %rsi,%r14
   a: mov    %rdi,%rbx
   d: mov    0x20(%rbx),%rax
  11: cmp    $0x3,%rax
  15: ja     2d <outofbounds(matrix const&, char const*)+0x2d>
  17: mov    (%rbx),%rax
  1a: mov    $0x4,%esi
  1f: mov    $0x2,%edx
  24: mov    %rbx,%rdi
  27: callq  *(%rax)
  29: mov    0x20(%rbx),%rax
  2d: lea    (%rax,%rax,2),%rax
  31: mov    0x8(%rbx),%rcx
  35: movsd  0x8(%rcx,%rax,8),%xmm0
  3b: lea    0x149(%rip),%rdi        # 18b <__clang_call_terminate+0xb>
         3e: DISP32  .cstring-0x18b
  42: mov    $0x1,%al
  44: mov    %r14,%rsi
  47: pop    %rbx
  48: pop    %r14
  4a: pop    %rbp
  4b: jmpq   50 <outofbounds(checkedMatrix const&, char const*)>
         4c: BRANCH32   printf

The callq instruction is the vtable call. Because this function called through the base class object, and could represent a derived class object, such a call is required. Now look at the code for the uncheckedMatrix class where the handleRangeError() had a no-op final override:

00000000000000a0 <outofbounds(uncheckedMatrix const&, char const*)>:
  a0: push   %rbp
  a1: mov    %rsp,%rbp
  a4: push   %r14
  a6: push   %rbx
  a7: mov    %rsi,%r14
  aa: mov    %rdi,%rbx
  ad: mov    0x20(%rbx),%rax
  b1: cmp    $0x3,%rax
  b5: ja     d0 <outofbounds(uncheckedMatrix const&, char const*)+0x30>
  b7: mov    (%rbx),%rax
  ba: mov    (%rax),%rax
  bd: mov    $0x4,%esi
  c2: mov    $0x2,%edx
  c7: mov    %rbx,%rdi
  ca: callq  *%rax
  cc: mov    0x20(%rbx),%rax
  d0: lea    (%rax,%rax,2),%rax
...

We still have an unnecessary vtable call. This must be a call to handleRangeError(), but that has a final override, and could conceivably be inlined. Some experimentation shows that it is possible to get the desired behaviour (Apple LLVM version 7.3.0 (clang-703.0.31)), but only when the final call is a leaf function. Explicit override of the base class element access operator to omit the check-and-throw logic

/**
   Explicitly unchecked matrix element access
 */
class uncheckedMatrix2 : public matrix
{
public:
   // inherit constructors:
   using matrix::matrix ;

   T operator()( const indexType i, const indexType j ) const
   { 
      return access( i, j ) ;
   }
} ;

has much less horrible code

0000000000000100 <outofbounds(uncheckedMatrix2 const&, char const*)>:
 100: push   %rbp
 101: mov    %rsp,%rbp
 104: mov    0x8(%rdi),%rax
 108: mov    0x20(%rdi),%rcx
 10c: lea    (%rcx,%rcx,2),%rcx
 110: movsd  0x8(%rax,%rcx,8),%xmm0
 116: lea    0x6e(%rip),%rdi        # 18b <__clang_call_terminate+0xb>
         119: DISP32 .cstring-0x18b
 11d: mov    $0x1,%al
 11f: pop    %rbp
 120: jmpq   125 <outofbounds(uncheckedMatrix2 const&, char const*)+0x25>
         121: BRANCH32  printf
 125: data16 nopw %cs:0x0(%rax,%rax,1)

Now we don’t have any of the vtable related epilog and prologue code, nor the indirection required to make such a call. This code isn’t pretty, but isn’t actually that much worse than raw pointer or plain vector access:

void outofbounds( const std::vector<double> m, const char * s ) noexcept
{
   printf( "%s: %g\n", s, m[ 4*3+2-1 ] ) ;
}

void outofbounds( const double * m, const char * s ) noexcept
{
   printf( "%s: %g\n", s, m[ 4*3+2-1 ] ) ;
}

The first generates code like the following:

0000000000000130 <outofbounds(std::__1::vector<double, std::__1::allocator<double> >, char const*)>:
 130: push   %rbp
 131: mov    %rsp,%rbp 
 134: mov    (%rdi),%rax  
 137: movsd  0x68(%rax),%xmm0
 13c: lea    0x48(%rip),%rdi        # 18b <__clang_call_terminate+0xb>
         13f: DISP32 .cstring-0x18b
 143: mov    $0x1,%al
 145: pop    %rbp
 146: jmpq   14b <outofbounds(std::__1::vector<double, std::__1::allocator<double> >, char const*)+0x1b>
         147: BRANCH32  printf
 14b: nopl   0x0(%rax,%rax,1)

Using vector instead of raw array access imposes only a single instruction dereference penalty:

0000000000000150 <outofbounds(double const*, char const*)>:
 150: push   %rbp
 151: mov    %rsp,%rbp
 154: movsd  0x68(%rdi),%xmm0
 159: lea    0x2b(%rip),%rdi        # 18b <__clang_call_terminate+0xb>
         15c: DISP32 .cstring-0x18b
 160: mov    $0x1,%al
 162: pop    %rbp
 163: jmpq   168 <GCC_except_table2>
         164: BRANCH32  printf

With the final override in a leaf function, or a similar explicit hiding of the base class function, we add one additional instruction overhead (one additional load).

pointer to member

This is a somewhat obscure feature. I don’t think that it is new to c++11, but I’ve never seen it used in 20 years. The only thing interesting about it is that the pointer to member objects apparently are entirely offset based, so could be used in shared memory interprocess configurations (where virtual functions cannot!)

Example of writing a class that implements c++11 range based for helpers

June 28, 2016 C/C++ development and debugging. , ,

If a class provides begin and end functions returning iterator objects, and that iterator has a != operator, then the class can be used in a range based for. Here’s an example that allows for iterating over all the bits in an integer. For example, suppose that

0b10101010

is a representation of the set:

128, 32, 8, 2

or

1<<7, 1<<5, 1<<3, 1<<1

We can iterate over the set with a set of bit shifts, and use the following setup to do so

class bititer
{
   unsigned bset ;
   int cur{} ;
 
public:

   bititer( const unsigned b )
      : bset{ b }
   {
   }

   bititer & operator++()
   {
      bset >>= 1 ;
      cur++ ;

      return *this ;
   }

   unsigned operator*()
   {
      unsigned v{} ;

      if ( bset & 1 )
      {
         v = ( 1 << cur ) ;
      } 

      return v ;
   }

   bool operator !=( const bititer & b )
   {
      return ( bset != b.bset ) ;
   }
} ;

Iteration can now be done once a container adapter that provides the begin and end functions is implemented:

struct bitset
{
   unsigned bits ;

   bititer begin()
   {
      return bititer{ bits } ;
   }

   bititer end()
   {
      return bititer{ 0 } ;
   }
} ;

int main()
{
   for ( auto v : bitset{ 0b10101010 } )
   {
      std::cout << v << "\n" ;
   }

   return 0 ;
}

Note that the 0b10101010 syntax is from c++14, not c++11.

Stroustrup reading notes: delagating constructors, default, delete, move, literals

June 26, 2016 C/C++ development and debugging. , , , , , , , ,

Here’s more notes from reading Stroustrup’s “The C++ Programming Language, 4th edition”

Alternate construction methods

I’d seen the new inline member initialization syntax that can be used to avoid (or simplify) explicit constructors. For example, instead of

struct physical
{
   double  c      ;  ///< wave speed
   double  tau    ;  ///< damping time
   double  x1     ;  ///< left most x value
   double  x2     ;  ///< right most x value

   /**
     set physical parameters to some defaults
    */
   physical() ;
} ;

physical::physical() :
   c{ 1.0 },
   tau{ 20.0 },
   x1{ -26.0 },
   x2{ +26.0 }
{
}

You can do

struct physical
{
   double c{ 1.0 }    ;  ///< wave speed
   double tau{ 20.0 } ;  ///< damping time
   double x1{ -26.0 } ;  ///< left most x value
   double x2{ +26.0 } ;  ///< right most x value
} ;

Much less code to write, and you can keep things all in one place. I wondered if this could be combined with constexpr, but the only way I could get that to work was to use static members, which also have to have an explicit definition (at least on Mac) to avoid a link error:

struct p2
{  
   static constexpr double x2{ +26.0 } ;  ///< right most x value
} ;
constexpr double p2::x2 ;

int main()
{  
   p2 p ;

   return p.x2 ;
}

But that is a digression. What I wanted to mention is that, while member initialization is cool, there’s more in the C++11 constructor simplification toolbox. We can write a constructor that builds on the member constructors (if any), but we can also make constructor specialations just call other constructors (called a delegating constructor), like so

struct physical
{
   double c{ 1.0 }    ;  ///< wave speed
   double tau{ 20.0 } ;  ///< damping time
   double x1{ -26.0 } ;  ///< left most x value
   double x2{ +26.0 } ;  ///< right most x value

   physical( const double cv ) : c{cv} {}
   physical( const double x1v, const double x2v ) : x1{x1v}, x2{x2v} {}

   physical( const double cv, const int m ) : physical{cv} { c *= m ; } ;
} ;

Stroustrup points out that the object is considered initialized by the time the delegating constructor is called. So if that throws, we shouldn’t get to the body of the constructor function

#include <iostream>

struct physical
{
   double c{ 1.0 }    ;  ///< wave speed

   physical( const double cv ) { throw 3 ; }

   physical( const double cv, const int m ) : physical{cv} { std::cout << "won't get here\n" ; }
} ;

int main()
try
{
   physical p{5} ;

   return 0 ;
}
catch (...)
{
   return 1 ;
}

default functions

If we define a structure with an explicit constructor with parameters, then unless explicit action is taken, this means that we no longer get a default constructor. Example:

#include <string>

struct F
{
   std::string s{} ;
   
   F( int n ) : s( n, 'a' ) {}
} ;

F x ;

This results in errors because the default constructor has been deleted by defining an explicit constructor

$ c++ -o d -std=c++11 d.cc
d.cc:10:3: error: no matching constructor for initialization of 'F'
F x ;
  ^
d.cc:7:4: note: candidate constructor not viable: requires single argument 'n', but no arguments were provided
   F( int n ) : s( n, 'a' ) {}
   ^
d.cc:3:8: note: candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 0 were provided
struct F
       ^
d.cc:3:8: note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 0 were provided
1 error generated.

We can get back the default constructor, without having to write it out explictly, by just doing:

#include <string>

struct F
{
   std::string s{} ;
   
   F( int n ) : s( n, 'a' ) {}

   F() = default ;
} ;

F x ;

It wouldn’t be a big deal to define an explicit default constructor above, just

    F() : s{} {}

but for a more complex class, being able to let the compiler do the work is nicer. Using = default also
means that the redundancy of specifying a member initializer and also having to specify the same initializer
in the default constructor member list is not required, which is nicer.

Note that like ‘= default’, you can use ‘= delete’ to tell the compiler not to generate any default for the member (or template specialization, …) if it would have if left unrestricted. This is similar to the trick of making destructors private:

class foo
{
   ~foo() ;
public:
// ...
} ;

Instead in c++11, you can write

class foo
{
public:
   ~foo() = delete ;
// ...
} ;

so instead of the compiler telling you there is unsufficent access to call the destructor, it should be able to tell you that an attempt to use a destructor for a class that has not defined one has been attempted. Note that this can be an explicitly deleted destructor, or one implicitly deleted (see below).

move operations

Back in university I once wrote a matrix class that I was proud of. It was reference counted to avoid really expensive assignment and copy construction operations, which were particularily bad for any binary operation that returned a new value

template <class T>
matrix<T> operator + ( const matrix<T> & a, const matrix<T> & b ) ;

C implementations of an addition operation (like the blas functions), wouldn’t do anything this dumb. Instead they use an interface like

template <class T>
void matrixadd( matrix<T> & r, const matrix<T> & a, const matrix<T> & b ) ;

This doesn’t have the syntactic sugar, but the performance won’t suck as it would if reference counting wasn’t used. I recall having a lot of trouble getting the reference counting just right, and had to instrument all my copy constructors, assignment operators and destructors with trace logging to get it all right. Right also depended on the compiler that was being used! I’ve still got a copy of that code kicking around somewhere, but it can stay where it is out of sight since move operations obsolete it all.

With move constructor and assignment operators, I was suprised to see them not kick in. These were the move operations

/// A simple square matrix skeleton, with instrumented copy, move, construction and destruction operators
class matrix
{
   using T = int ;                  ///< allow for easy future templatization.

   size_t            m_rows ;       ///< number of rows for the matrix.  May be zero.
   size_t            m_columns ;    ///< number of columns for the matrix.  May be zero.
   std::vector<T>    m_elem ;       ///< backing store for the matrix elements, stored in row major format.

public:

   /// move constructor to create 
   matrix( matrix && m )
      : m_rows{ m.m_rows }
      , m_columns{ m.m_columns }
      , m_elem{ std::move(m.m_elem) }
   {  
      m.m_rows = 0 ;
      m.m_columns = 0 ;
      //std::cout << "move construction: " << &m << " to " << this << " ; dimensions: (rows, columns, size) = ( " << rows() << ", " << columns() << ", " << m_elem.size() << " )\n" ;
   }

   /// move assignment operator.
   matrix & operator = ( matrix && m )
   {  
      //std::cout << "move operator=(): " << this << '\n' ;

      std::swap( m_columns, m.m_columns ) ;
      std::swap( m_rows, m.m_rows ) ;
      std::swap( m_elem, m.m_elem ) ;

      return *this ;
   }

   /// Create (dense) square matrix with the specified diagonal elements.
   matrix( const std::initializer_list<T> & diagonals )

//...
} ;

With the following code driving this

matrix f() ;
   
int m1()
{ 
   matrix x1 = f() ; 
   matrix x2 { f() } ;
      
   return x1.rows() + x2.rows() ;
}     

I was suprised to see none of my instrumentation showing for the move operations. That appears to be because the compiler is doing return value optimization, and constructing these in place in the stack storage locations of &x1, and &x2.

To get actual move construction, I have to explicitly ask for move, as in

matrix mg( {4, 5, 6} ) ;

int m0()
{
   matrix x2 { std::move( mg ) } ;

   return x2.rows() ;
}

and to get move assignment I could assign into a variable passed by reference, like

void g( matrix & m )
{
   m = matrix( {1,2,3} ) ;   
}

This resulted in a stack allocation for the diagonal matrix construction, then a move from that. For this assignment, the compiler did not have to be instructed to use a move operation (and the function was coded explicitly to prevent return value optimization from kicking in).

Note that if any of a copy, move, or destructor is defined for the class, a standards compliant compiler is supposed to also not generate any default copy, move or destructor for the class (i.e. having any such function, means that all the others are =delete unless explicitly defined).

Strange operator overload options

In a table of overloadable operators I see two weird ones:

  • ,
  • ->*

I’d never have imagined that there would be a valid reason to overload the comma operator, which I’ve only seen used in old style C macros that predated C99’s inline support. For example you could do

#define foo(x)    (f(x), g(x))

which might be equivalent to, say,

static inline int foo( int x )
{
   f( x ) ;

   return g(x) ;
}

However, sure enough a comma overloaded function is possible:

struct foo
{
   int m ;

   foo( int v = {} ) : m{v} {}

   int blah( ) const
   {
      return m + 3 ;
   }

   int operator,(const foo & f) 
   {
      return blah() + f.blah() ;
   }
} ;

int main()
{
   foo f ;
   foo g{ 7 } ;

   return f, g ;
}

This results in 7 + 0 + 3 + 3 = 13 as a return code. I don’t have any intention of exploiting this overloadable operator in any real code that I am going to write.

What is the ->* operation that can also be overloaded.

User defined literals

C++11 allows for user defined literal suffixes for constant creation, so that you could write something like

length v = 1.0009_m + 3_dm + 5.0_cm + 7_mm ;

User defined literals must begin with underscore. The system defined literals (such as the complex i, and the chrono ns from c++14) do have this underscore restriction. This is opposite to the user requirement that states no non-system code should define underscore or double-underscore prefixed symbols. I found getting the syntax right for such literals was a bit finicky. The constructor has to be constexpr, and you have to explicitly use long double or unsigned long long types in the operator parameters, as in

struct length
{
   double len {} ;

   constexpr length( double v ) : len{ v } {}
} ;

inline length operator + ( const length a, const length b )
{
   return length( a.len + b.len ) ;
}

constexpr length operator "" _m( long double v )
{
   return length{ static_cast<double>(v) } ;
}

constexpr length operator "" _dm( long double v )
{
   return length{ static_cast<double>(v/10.0) } ;
}

constexpr length operator "" _cm( long double v )
{
   return length{ static_cast<double>(v/100.0) } ;
}

constexpr length operator "" _mm( long double v )
{
   return length{ static_cast<double>(v/1000.0) } ;
}

constexpr length operator "" _m( unsigned long long v )
{
   return length{ static_cast<double>(v) } ;
}

constexpr length operator "" _dm( unsigned long long v )
{
   return length{ static_cast<double>(v/10.0) } ;
}

constexpr length operator "" _cm( unsigned long long v )
{
   return length{ static_cast<double>(v/100.0) } ;
}

constexpr length operator "" _mm( unsigned long long v )
{
   return length{ static_cast<double>(v/1000.0) } ;
}

string literals

It’s mentioned in the book that one can use an s suffix for string literals so that they have std::string type. However, what isn’t stated is that this requires both c++14 and the use of the std::literals namespace. The following illustrates how this feature can be used

#include <string>
#include <iostream>

static_assert( __cplusplus >= 201402L, "require c++14 for string literal suffix" ) ;

using namespace std::literals ;

int main()
{
   std::string hi { "hi\n" } ;
   hi += "there"s + "\n" ;

   std::cout << hi ;

   return 0 ;
}

Note that without the literal s suffix in the string concatonation, as in

   hi += "there" + "\n" ;

This produces an error:

$ make
c++ -o d -std=c++14 d.cc
d.cc:11:18: error: invalid operands to binary expression ('const char *' and 'const char *')
   hi += "there" + "\n" ;
         ~~~~~~~ ^ ~~~~
1 error generated.
make: *** [d] Error 1

The language isn’t designed to know to promote the right hand side elements to std::string just because they are being assigned to such a type. The use of either the string literal suffix, or an explicit conversion is required, as in

hi += std::string{"there"} + "\n" ;