Thursday, November 19, 2015

C++ lambda inheritance

I was thinking about if we are able to inherit from a C++ lambda (say, anonymous class)

My first try was like this, use a helper function to forward the lambda body and store that as an private member of a class. But this is a HAS-A relationship, not really inherited from the lambda.

#include <iostream>
#include <utility>

template<typename lambda>
class Foo {
  lambda _t;
  int x = 5566;

public:
  Foo(lambda &&t) : _t(std::forward<lambda>(t)) {
    std::cout << "Foo()" << std::endl;
  }

  ~Foo() {
    std::cout << "~Foo()" << std::endl;
  }

  void operator()(void) {
    _t(x);
  }

  void operator()(int x) {
    std::cout << "Foo(int): " << x << std::endl;
  }
};

template<typename lambda>
Foo<lambda> make_class(lambda &&t) {
  return { std::forward<lambda>(t) };
}


int main (void) {
  auto qq = make_class([](int x) -> void {
    std::cout << "operator(int): " << x << std::endl;
  });

  qq();
  qq(7788);

  return 0;
}


Foo()
operator(int): 5566
Foo(int): 7788
~Foo()



suhorngT improved this as a real inheritance:


#include <iostream>
#include <utility>

template<typename lambda>
class Foo : public lambda {

public:
    Foo(lambda &&t) : lambda(t) {
      std::cout << "Foo()" << std::endl;
    }

    ~Foo() {
      std::cout << "~Foo()" << std::endl;
    }
};

template<typename lambda>
Foo<lambda> make_class(lambda &&t) {
  return { std::forward<lambda>(t) };
}


int main (void) {
  auto qq = make_class([](int x) -> void {
    std::cout << "operator(int): " << x << std::endl;
  });

  qq(123);
  return 0;
}




Foo()
operator(int): 123
~Foo()

After that I took out the make_class helper, and use decltype instead, make the syntax much better.


#include <iostream>

template<typename... lambda>
class Bar : public lambda... {

public:
  Bar(lambda... l) : lambda(l)... {
    std::cout << "Bar()" << std::endl;
  }

  void foo(void) {
    std::cout << "foo()" << std::endl;
  }
};


int main(void)  {
  int a = 55;

  auto gg = [a](int b) -> void {
    std::cout << "operator(): " << a << b << std::endl;
  };

  auto qq = Bar<decltype(gg)>(gg);

  qq(66);
  qq.foo();

  return 0;
}



Bar()
operator(): 5566
foo()


Reference:
http://cpptruths.blogspot.tw/2014/05/fun-with-lambdas-c14-style-part-2.html
http://cpptruths.blogspot.com/2014/03/fun-with-lambdas-c14-style-part-1.html

Friday, November 13, 2015

gdb pretty-print python path


On some of my dev machines (freaking Ubuntu 14.04), gdb can't find the pretty print python extension.

(^q^) r
Starting program: /home/xatier/xxxxx
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Traceback (most recent call last):
  File "/usr/share/gdb/auto-load/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19-gdb.py", line 63, in <module>
    from libstdcxx.v6.printers import register_libstdcxx_printers
ImportError: No module named 'libstdcxx'


Let's print python path:


On Ubuntu 14.04
(^q^) python print(sys.path)
['/usr/share/gdb/python', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-x86_64-linux-gnu', '/usr/lib/python3.4/lib-dynload', '/usr/local/lib/python3.4/dist-packages', '/usr/lib/python3/dist-packages']

On arch linux
(^q^) python print(sys.path)
['/usr/lib/../share/gcc-5.2.0/python', '/usr/share/gdb/python', '/usr/lib/python35.zip', '/usr/lib/python3.5', '/usr/lib/python3.5/plat-linux', '/usr/lib/python3.5/lib-dynload', '/usr/lib/python3.5/site-packages']


See? So basically the python scripts are under /usr/share/<gcc-ver>/python

$ ls /usr/share | grep gcc
gcc-4.8


Just add this line to your ~/.gdbinit :

python sys.path.append("/usr/share/gcc-4.8/python")


Now you are good.

(^q^) python print(sys.path)
['/usr/share/gdb/python', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-x86_64-linux-gnu', '/usr/lib/python3.4/lib-dynload', '/usr/local/lib/python3.4/dist-packages', '/usr/lib/python3/dist-packages', '/usr/share/gcc-4.8/python']


STL vector out-of-bound access is an undefined behavior


Found a bug today, which is a well-known pitfall in C++.

Consider the following code, std::vector::operator[] won't perform any boundary check on the index, a out-of-bound access is an undefined behavior.

#include <vector>                                                               
#include <iostream>                                                             
                                                                                
int main (void) {                                                               
  std::vector<bool> a(10);                                                      
                                                                                
  for (auto x : a)                                                              
      x = true;                                                                 
                                                                                
  if (a[11] == false)                                                           
      std::cout << "gg";                                                        
                                                                                
  return 0;                                                                     
}


gg

----

On the other hand, std::vector::at will yield an exception on out-of-bound access.


#include <vector>                                                               
#include <iostream>                                                             
 
int main (void) {                                                               
  std::vector<bool> a(10);                                                      
 
  for (auto x : a)                                                              
      x = true;                                                                 
 
  if (a.at(11) == false)                                                           
      std::cout << "gg";                                                        
 
  return 0;                                                                     
}


terminate called after throwing an instance of 'std::out_of_range'
what(): vector::_M_range_check: __n (which is 11) >= this->size() (which is 10)