Android with root Git for version control Lircd with Raspberry Pi for IR receiver and sender Tips for Windows Depolying your own password management tool -- KeeWeb Depoly your flask app into Heroku Fix shit IE code manually ISBN to Book Category by Scraping DangDang A Generic Makefile for C/C++ Program Configure Raspberry pi Remove watermark with PyPDF2 tips for docker Anaconda+TensorFlow+CUDA Snippets Configure Remote Mathematica Kernel Build your own ngrok server Access Array SSL VPN 使用Rstudio制作html5幻灯片 tips for Mac OS X system Tips for ipython notebook 配置Ubuntu server + Openbox (Obuntu) tips for Vimperator tips for Vim 安装CUDA My First Jekyll Blog rsync常见选项 在Linux中读取Ipod touch的文件 tip for texmacs 在VPS上建站的一些tip Gnuplot绘图札记 Samba系统和autofs自动挂载 Linux中alsamixer声卡无法录音 搭建自己的RSS订阅器——Tiny Tiny RSS Grub2引导安装Ubuntu awk tips 将Ubuntu系统装入U盘 The Great Rtorrent 编译GCC 再这样剁手!!!该死的libgd 使用ulimit进行资源限制 使用SSH代理上IPV6 使用RCurl抓取网页数据 修复Ubuntu Grub记 openbox中的文件关联 在Ubuntu 12.04下编译qtiplot 处理BCM4312网卡驱动纪实 配置我的Ubuntu Server记 Cygwin杂记 Linux 使普通用户具有以超级权限执行脚本 让firefox自定义地处理文件类型 WordPress优秀主题及插件 在phpcloud上搭建wordpress UBUNTU下用pptpd做VPN server ubuntu升级内核过后的一些问题 安装telnet服务 kubuntu札记 64位kubuntu札记 统计软件R Virtualbox stardict星际译王 Ubuntu重装windows系统后的grub引导修复 SSH服务及花生壳域名解析 采用cbp2make工具由code::blocks工程创建makefile文件 UBUNTU 札记

tips for C/C++

2015年08月11日

Programming Suggestion

Do not use Macro to pre-process source file

In legacy c99 one common skill is to use #if to conditionally remove code piece, and this is done in the compiler pre-process stage. In other words, the same effect as removing that part of code directly from the file.

The down side of this technique is that modern IDE lost awareness of that part of code and some operations like rename an variable, refactor function definition totally missed those code pieces. After sometime, another person can not easily turn off those #if easily because of big code change, lost context, etc.

But how to achieve similar effect? I personally do it like following example:

// use static const (or constexpr) to serve MACRO purpose
static const bool ENABLE_LOG = 0==1;

int has_three_args(int argc){
    return 3==argc;
}

int main(int argc, char *argv[]){
    // use `if` statement  with compile time deterministic condition to serve `#if` purpose
    if (1==1 && ENABLE_LOG){
        return has_three_args(argc);
    }

    return 0;
}

Try compile it with minimal as O1 level optimization, c++ -c -O1 main.cpp && objdump -dr main.o. You can see the if section is completely removed from main function. The same effect as #if achieved.

Disassembly of section .text:

0000000000000000 <_Z14has_three_argsi>:
   0:	83 ff 03             	cmp    $0x3,%edi
   3:	0f 94 c0             	sete   %al
   6:	0f b6 c0             	movzbl %al,%eax
   9:	c3                   	retq   

000000000000000a <main>:
   a:	b8 00 00 00 00       	mov    $0x0,%eax
   f:	c3                   	retq   

CoreDump debugging

To simulate a segment fault crash,

  1. Run ulimit -c unlimited to enable core dump saving.
  2. Start the executable like catchsegv sleep 1m (catchsegv help print the stack trace info when crash).
  3. pgrep -af sleep to find out the PID of the executable.
  4. kill -11 $PID to send a SIGSEGV(11) signal to the process to trigger crash.
  5. Find core dump file under /var/lib/systemd/coredump/. The path or saving pattern can be configured with like echo '|/root/bin/pipe-script.py %P' > /proc/sys/kernel/core_pattern.
  6. Analysis the core dump with gdb --tui -q /usr/bin/sleep ./core.sleep.

Easy to make mistake

  • 需要在std命名空间内重载STL容器(如std::vector)的比较操作符,否则不会被诸如std::set等容器自动应用。

  • 类数组delete 基本类型的对象没有析构函数,所以回收基本类型组成的数组空间用 delete 和 delete[] 没有区别。但是对于类对象数组,只能用 delete[]。

  • switch语句中case跳过变量初始化的问题

    case语句中不允许直接定义变量,因为当此case条件不被执行时变量将无法初始化。解决的办法是case后面的结构用{}括起来以限制变量的作用域。如

      switch (a)
      {
          case 0:
              POINTS p = *(POINTS *)a;
              int i = 0;
              break;
          case 1:
              break;
      }
    

    编译报错:error C2360: initialization of 'i' is skipped by 'case' label

    用这样写才对:

      switch (a)
      {
          case 0:
          {
              POINTS p = *(POINTS *)a;
              int i = 0;
              break;
          }
          case 1:
          break;
      }
    
  • Do not predfine istream_iterator as the The first object is read when the iterator is constructed: std::istream_iterator<float> inputIter(inputFile);

Code snippets

  • Solve static variable in class template can not be partial specification.

      template<typename T>
      T _default_value() {
          return T();
      }
    
      template<>
      float _default_value<float>() {
          return -1;
      }
    
    
      //typedef int T;
      template<typename T>
      class CL
      {
      public:
          typedef decltype(fabs(T() - T())) TD;
    
      public:
          CL() {}
          ~CL() {}
    
          TD get(int i, int j) {
              return default;
          }
    
    
      private:
          static const TD default;
      };
    
      template<typename T>
      const typename CL<T>::TD CL<T>::default = _default_value<CL<T>::TD>();
    
  • Get value type of pointer

      #include <iostream>
      template<typename T>
      struct DECAY
      {
          typedef decltype(**(T*)NULL) type;
      };
    
      int main(int argc, char *argv[])
      {
          const char *cc=NULL;
    
          typename DECAY<decltype(cc)>::type x = *cc; //reference, nothing happend when x is accessed, so no runtime error here
          std::cout << typeid(x).name() << std::endl;
            
          typename std::decay<decltype(*cc)>::type y=*cc; //assign, runtime error when cc==NULL
          std::cout << typeid(y).name() << std::endl;
            
      }
    
  • Singleton

      #include <iostream>
      #include <memory>
      #include <map>
      class Singleton
      {
      public:
          static Singleton& GetInstance(size_t id = 0) {
              static std::map<size_t, std::unique_ptr<Singleton>> mpInstance;
              if (mpInstance.find(id) == mpInstance.end()) {
                  printf("New singleton request: %d \n", id);
                  mpInstance[id] = std::unique_ptr<Singleton>(new Singleton(id)); //unique_ptr will make sure new got delete and not pointer transfered
              }
              else {
                  printf("Old singleton request: %d \n", id);
              }
              return *mpInstance[id];
          }
    
          ~Singleton() {
              printf("I am died: %d -> %x\n", id, this);
          }
    
    
      private:
          size_t id;
          Singleton(size_t _id):id(_id){
              printf("I am borned: %d -> %x\n", id, this);
          }
          Singleton(const Singleton&) {}
          Singleton(Singleton&&) {}
      };
    
    
      int main(int argc, char *argv[])
      {
          ErrorCode e, result = SUCCESS;
    
          printf("Main started\n");
          Singleton& x = Singleton::GetInstance(0);
          printf("Got it: %d -> %x\n", 0, &x);
          Singleton& y = Singleton::GetInstance(1);
          printf("Got it: %d -> %x\n", 1, &y);
          Singleton& z = Singleton::GetInstance(0);
          printf("Got it again: %d -> %x\n", 0, &z);
          printf("Main exit\n");
          return 0;
      }
    
  • boost example
      #include <iostream>
      #include <fstream>
      #include <iomanip>
      #include <boost/filesystem.hpp>
        
      int main(int argc, char *argv[])
      {
          const bool debug_print = true;
          if (debug_print) {
              debug_fp = new std::ofstream("1.txt", std::ios::app);
          }
            
          if (debug_print) {
              *debug_fp << std::setprecision(10) << 1.0 << "\n";
          }
            
          if (debug_print) {
              debug_fp->close();
              delete debug_fp;
                
              boost::filesystem::copy_file(".\\1.txt", ".\\2.txt");
          }
            
          return 0;
      }
    
  • std::multimap for count unique values
      #include <iostream>
      #include <map>
    
      int main(int argc, char *argv[])
      {
          std::multimap<int, size_t> keyvalue;
          // initialize
          for (size_t j = 0; j < 19; j++)
          {
              keyvalue.insert(std::make_pair(j%5, j));
          }
    
          // count unique keys
          auto key = keyvalue.begin()->first;
          const size_t nkey = 1 + std::count_if(keyvalue.begin(), keyvalue.end(),
              [&key](const auto& s) {
              if (s.first != key) {
                  key = s.first;
                  return true;
              }
              else {
                  return false;
              }
          });
    
          // iterate every key group
          auto kv = keyvalue.begin();
          for (size_t g = 0; kv != keyvalue.end(); kv = keyvalue.upper_bound(kv->first), ++g)
          {//for every key group
    
              auto krange = keyvalue.equal_range(kv->first);
              std::cout<<"Got "<<std::distance(krange.first, krange.second)<<" values with key" << kv->first << std::endl;
    
              for (auto kiter = krange.first; kiter != krange.second; kiter++)
              {// for every value
                  std::cout << "  " << kiter->first << " - " << kiter->second << std::endl;
              }
          }
            
          return 0;
      }
    
  • Mordern C++: Reference
      /*********************************************************************
      std::vector<class>::push_back and std::make_pair
      **********************************************************************/
      class PairC
      {
      public:
          PairC() {
              std::cout << "Created " << count << " times.";
              count++;
          }
          ~PairC() {
              std::cout << "Deleted " << count << " times.";
              count--;
          }
    
      private:
          static int count;
      };
    
      int PairC::count = 0;
    
      std::vector<PairC> ReturnPair() {
          std::vector<PairC> x;
          x.resize(2);
          return std::move(x);
      }
    
      int main(int argc, char *argv[])
      {
          std::vector<std::pair<int, std::vector<PairC>>> x;
          x.push_back(make_pair(1, ReturnPair()));
            
          return 0;
      }
    
      /*********************************************************************
      Move constructor
      **********************************************************************/
      #include <iostream>
      #include <vector>
    
      class ITEM
      {
      public:
          ITEM() {
              id = _id++;
              std::cout << "item " << id << " created\n";
          }
          ~ITEM() {
              std::cout << "item " << id << " removed\n";
          }
    
          int id;
          static int _id;
    
      private:
      };
    
      int ITEM::_id = 0;
    
      std::vector<ITEM> right_reference(int nth) {
          std::vector<ITEM> x(2);
          return std::move(x);
      }
    
      class ST
      {
      public:
          ST(int nth):vec(right_reference(nth)) {
          }
          ~ST() {
              std::cout << " -- " << vec.size() << " items left -- \n";
          }
    
          ST(const ST& v):vec(v.vec) {
                
          }
          ST(ST&& v):vec(std::move(v.vec)) {
          }
    
          std::vector<ITEM> vec;
      private:
            
      };
    
      ST right_reference_VEC(int nth) {
          ST x(nth);
          return std::move(x);
      }
    
      int main(int argc, char *argv[])
      {
          ST x = right_reference_VEC(2);
          std::cout << " -- " << x.vec.size() << " items here -- \n";
          std::cout << "item " << x.vec[0].id << " read\n";
          std::cout << "item " << x.vec[1].id << " read\n";
          return 0;
      }
    
    
      /*********************************************************************
      Reference in STL container
      **********************************************************************/
      #include <iostream>
      #include <vector>
      #include <algorithm>
      #include <iterator>
    
      class ObjTracker
      {
      public:
          ObjTracker() {
              id = n++;
              p = this;
              std::cout<<"raw construct "<<id<<" : ";
              say();
          }
          ~ObjTracker(){
              std::cout<<"raw destroy "<<id<<" : ";
              say();
              p = nullptr;
          }
    
          ObjTracker(const ObjTracker&) = delete;
          ObjTracker(ObjTracker&&) = delete;
    
          void say() const {
              std::cout<<"I am "<<id<<" with $"<<p<<"$"<<std::endl;
          }
    
          static void report() {
              std::cout<<"==== Total "<<n<<" objects created ====";
          }
    
      private:
          static int n;
          int id;
          void* p;
      };
      int ObjTracker::n=0;
    
    
      class ObjTrackerWrapper
      {
      public:
          ObjTrackerWrapper() = delete;
      //    ObjTrackerWrapper(const ObjTrackerWrapper&) = delete;
      //    ObjTrackerWrapper(ObjTrackerWrapper&&) = delete;
          ObjTrackerWrapper(const ObjTrackerWrapper& ohs):content(ohs.content){
              p = this;
              std::cout<<"wrapper rh construct : ";
              say();
          };
    
          ObjTrackerWrapper(ObjTrackerWrapper&& ohs):content(ohs.content){
              p = this;
              std::cout<<"wrapper move construct : ";
              say();
          };
    
          ObjTrackerWrapper(ObjTracker& obj):content(obj){
              p = this;
              std::cout<<"wrapper normal construct : ";
              say();
          }
    
          ~ObjTrackerWrapper(){
              std::cout<<"wrapper destroy : ";
              say();
          }
    
          void say() const {
              std::cout<<"I am wrapper "<<p<<" for $"<<&content<<"$ , it say : ";
              content.say();
          }
    
      private:
          ObjTracker& content;
          void* p;
      };
    
      class WatchDog
      {
      public:
          WatchDog() {}
          ~WatchDog(){
              ObjTracker::report();
          }
      } _;
    
      int main()
      {
          std::cout<<"==== main started ===="<<std::endl;
          std::vector<ObjTracker> a(2);
          std::cout<<"==== raw created ===="<<std::endl;
          std::vector<ObjTrackerWrapper> b;
          std::cout<<"==== wrapper created ===="<<std::endl;
          std::copy(
                      a.begin(),
                      a.end(),
                      std::back_insert_iterator<std::vector<ObjTrackerWrapper>>(b)
                      );
          std::cout<<"==== copy completed ===="<<std::endl;
    
          for(auto& i: b){
              i.say();
          }
    
          std::cout<<"==== main exit here ===="<<std::endl;
    
          return 0;
      }
    
  • Designated initializer C99 not supported in C++11

      struct MyStruct
      {
          int a;
          int b;
      };
    
      MyStruct x = {.a=1, .b=2} ;
    
  • 在字符串中删除某个字符,STL的妙用

      #include <iostream>
        
      #include <string>
      #include <algorithm>
      #include <functional>
    
      using namespace std;
    
      int main(int argc, const char *argv[])
      {
    
          string str(" d df df ");
          string::iterator new_end = remove_if(str.begin(), str.end(), bind2nd(equal_to<char>(), ' '));
    
          str.erase(new_end, str.end());
          cout << str << endl;
          return 0;
      }
    

Tips:

  • STL internal: deconstructor can be called explicity. See xmemory0 for how std::vector destruct an object when .pop_back with the help of std::allocator

      template<class _Uty>
          void destroy(_Uty *_Ptr)
          {	// destroy object at _Ptr
          _Ptr->~_Uty(); // **this line of code will be skiped for build-in types**
          }
    
  • Use command cpp -dM -E -xc++ /dev/null and cc -dM -E -xc /dev/null to check build-in macros. Or check macros definiation place in the source code while processing

      gcc -E $CompileOptions $SourceFile | \
      egrep "^# " | grep -v '<'| cut -f 2 -d '"' | \
      sort | uniq |
      while read line
          do
                  grep -l $MacroName $line
          done
    
  • Dealing with macro in C++
      // use g++ -E main.cpp -o main.i to pre-process the file
      #include <iostream>
      void __print_macro_value__() {
      #define __PRINT__MACRO__(x) std::cout<<"value of "<<(#x)<<" is "<<(x)<<std::endl
          __PRINT__MACRO__(__cplusplus);
      #undef __PRINT__MACRO__
      }
    
  • In gdb, useset print elements {200|unlimited} and print *{pArray}@{len} to print all the contents of pArray[]. Use p (char*)m_path to print a string.

  • Ubuntu安装Sqlite3

    安装数据库系统Sqlite3:

      apt-get install sqlite sqlite3
      #注:在程序中使用Sqlite3
    

    编译还需要安装Sqlite3编译需要的工具包:

      apt-get install libsqlite3-dev
    

    包含头文件#include <sqlite3.h>,编译时在连接器选项中加入选项-lsqlite3