使用IWYU整理头文件引用

0x01 介绍

IWYU 是include what you use的首字母缩写
IWYU 使用clang分析符号的引用。是google的一个项目,它可以给出应该引用和移除
的头文件,但并不能保证 100% 是正确的(当然都是语言特性的原因)。

0x02 编译源码包

  • 安装clang
  • 检查clang的版本并下载对应版本的IWYU源码

  • 编译
    • tar xvf include-what-you-use-clang_3.4.tar.gz
    • mkdir build && cd build
    • cmake -G "Unix Makefiles" -DLLVM_PATH=/usr/lib/llvm-3.4 ../include-what-you-use-clang_3.4
    • make

0x03 举例

  • c++ 源码 mem.cc

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    #include <fcntl.h>
    #include <signal.h>
    #include <stdio.h>
    //#include <stdlib.h>
    #include <string.h>
    #include <stdint.h>
    #include <sys/mman.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <sys/user.h>
    #include <execinfo.h>

    #include <thread>
    using namespace std;

    void g()
    {
    usleep(2000);
    printf("thread one\n");
    }

    void f()
    {
    printf("thread two\n");
    }

    int main(int argc, char* argv[])
    {
    std::thread t1(f);
    std::thread t2(g);
    t1.join();
    t2.join();
    return 0;
    }
  • 检查, 注意,要使用-std=c++11, 因为这里使用c11的线程库

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    dennis@dennis:~/Downloads/build$ ./include-what-you-use -std=c++11 mem.cc 

    mem.cc should add these lines:

    mem.cc should remove these lines:
    - #include <execinfo.h> // lines 11-11
    - #include <fcntl.h> // lines 1-1
    - #include <signal.h> // lines 2-2
    - #include <stdint.h> // lines 6-6
    - #include <string.h> // lines 5-5
    - #include <sys/mman.h> // lines 7-7
    - #include <sys/stat.h> // lines 8-8
    - #include <sys/user.h> // lines 10-10

    The full include-list for mem.cc:
    #include <stdio.h> // for printf
    #include <unistd.h> // for usleep
    #include <thread> // for thread
    ---
  • 修改

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //#include <fcntl.h>
    //#include <signal.h>
    #include <stdio.h>
    //#include <stdlib.h>
    //#include <string.h>
    //#include <stdint.h>
    //#include <sys/mman.h>
    //#include <sys/stat.h>
    #include <unistd.h>
    //#include <sys/user.h>
    //#include <execinfo.h>
  • 再次检查,显示已正确引用或前向声明

    1
    2
    3
    dennis@dennis:~/Downloads/build$ ./include-what-you-use -std=c++11 mem.cc 

    (mem.cc has correct #includes/fwd-decls)

0x04 参考

understand gcc assembly output

0x00 generate assembly code when compile

gcc -S -o test.s test.c

sample code

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>

int main(int argc, char* argv[])
{
int i = 0;
for (i=0; i<10; i++) {
printf("hello123");
}
return 0;
}

assembly code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
	.file	"test.c"
.section .rodata
.LC0:
.string "hello123"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $32, %rsp
movl %edi, -20(%rbp)
movq %rsi, -32(%rbp)
movl $0, -4(%rbp)
movl $0, -4(%rbp)
jmp .L2
.L3:
movl $.LC0, %edi
movl $0, %eax
call printf
addl $1, -4(%rbp)
.L2:
cmpl $9, -4(%rbp)
jle .L3
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4"
.section .note.GNU-stack,"",@progbits

0x01 basic acknowledge of assembly [AT&T]

  • Register
  • Move

0x02 Reference

speed up c++ compilation

How c++ compilor work?

Speed up tips

  • check code
    • Don’t include not needed headers, use forward declaration for class if possible
    • Pimpl (pointer to implementation), interface and implement do their job clear
    • Reduce interdependency
    • Clean not needed headers
    • inline and template
    • Guard Conditions
  • other tips
    • PCH (Previous Compile Header)
    • Unity Build
    • ccache
  • compile resource
    • parallel compile, compile multiple modules at the same times
    • use more faster computer
    • distribute compile

Reference

Hexo

Why leave jekyll and move to hexo

  • Jekyll
    • markdown syntax parsing change on github, and after my modify it not work as
      before (so sad ;( )
    • Jekyll use ruby
  • hexo
    • Hexo use node.js
    • Have good themes

What is hexo

A fast, simple & powerful blog framework
see https://hexo.io/ for more

Installation

  • mkdir hexo
  • hexo init
    • if fail to install depenances auto, install them manually.
      • cat package.json, and look at the object of dependencies, just install them
      • npm install xxx --save
      • you can list installed modules by ls node_modules
  • modify _config.yml, here is my changes:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    diff --git a/_config.yml b/_config.yml
    index 26c27e9..9b0b32c 100644
    --- a/_config.yml
    +++ b/_config.yml
    @@ -3,11 +3,12 @@
    ## Source: https://github.com/hexojs/hexo/

    # Site
    -title: Hexo
    +title: Matrix207's Blog
    subtitle:
    description:
    -author: John Doe
    -language:
    +author: Matrix207
    +language: zh-Hans
    +#language:
    timezone:

    # URL
    @@ -28,7 +29,7 @@ i18n_dir: :lang
    skip_render:

    # Writing
    -new_post_name: :title.md # File name of new posts
    +new_post_name: :year-:month-:day-:title.md # File name of new posts
    default_layout: post
    titlecase: false # Transform title into titlecase
    external_link: true # Open external links in new tab
    @@ -63,9 +64,17 @@ pagination_dir: page
    # Extensions
    ## Plugins: https://hexo.io/plugins/
    ## Themes: https://hexo.io/themes/
    -theme: landscape
    +#theme: landscape
    +theme: hexo-theme-next/

    # Deployment
    ## Docs: https://hexo.io/docs/deployment.html
    deploy:
    - type:
    + type: git
    + repository: github.com:matrix207/matrix207.github.com.git
    + branch: master
    +
    +# Toc
    +toc:
    + maxDepth: 3
    +

Select theme: hexo-theme-next or landscape

  • compare these two themes, I like hexo-theme-next more than landscape. But

What features I need

  • menus

Tips for fixing issues

Reference

malloc

Algorithms

The main properties of the algorithms are:

  • For large (>= 512 bytes) requests, it is a pure best-fit allocator,
    with ties normally decided via FIFO (i.e. least recently used).
  • For small (<= 64 bytes by default) requests, it is a caching
    allocator, that maintains pools of quickly recycled chunks.
  • In between, and for combinations of large and small requests, it does
    the best it can trying to meet both goals at once.
  • For very large requests (>= 128KB by default), it relies on system
    memory mapping facilities, if supported.

Test

  • test code

    // gcc -o t t.c
    #include <stdio.h>
    #include <stdlib.h>
    
    #define ARRAY_SIZE(x) sizeof(x)/sizeof(x[0])
    
    void test(size_t require)
    {
        char* p = malloc(require);
        char* q = malloc(1);
        size_t size = malloc_usable_size(p);
        printf("memory require %lu, allocated %lu, address %p, next address %p, dis %ld\n",
                require, size, p, q, q-p);
        free(p);
        free(q);
    }
    
    int main()
    {
        int fast_bin[] = {1, 2, 4, 8, 20, 24};
        int small_bin[] = {25, 30, 40, 41, 50, 60, 64, 70, 72, 73};
        int large_bin[] = {1024, 128*1024, 135*1024, 256*1024, 512*1024, 1024*1024};
        int i=0;
        printf("-----------Fast bin: memory pool-------------\n");
        for (i=0;i<ARRAY_SIZE(fast_bin);i++) {
            test(fast_bin[i]);
        }
        printf("-----------Samll bin-------------\n");
        for (i=0;i<ARRAY_SIZE(small_bin);i++) {
            test(small_bin[i]);
        }
        printf("-----------Large bin-------------\n");
        for (i=0;i<ARRAY_SIZE(large_bin);i++) {
            test(large_bin[i]);
        }
        return 0;
    }
    
  • test

    dennis@dennis:~/tt$ ./t
    -----------Fast bin-------------
    memory require 1, allocated 24, address 0x6ea010, next address 0x6ea030, dis 32
    memory require 2, allocated 24, address 0x6ea030, next address 0x6ea010, dis -32
    memory require 4, allocated 24, address 0x6ea010, next address 0x6ea030, dis 32
    memory require 8, allocated 24, address 0x6ea030, next address 0x6ea010, dis -32
    memory require 20, allocated 24, address 0x6ea010, next address 0x6ea030, dis 32
    memory require 24, allocated 24, address 0x6ea030, next address 0x6ea010, dis -32
    -----------Samll bin-------------
    memory require 25, allocated 40, address 0x6ea050, next address 0x6ea010, dis -64
    memory require 30, allocated 40, address 0x6ea050, next address 0x6ea010, dis -64
    memory require 40, allocated 40, address 0x6ea050, next address 0x6ea010, dis -64
    memory require 41, allocated 56, address 0x6ea080, next address 0x6ea010, dis -112
    memory require 50, allocated 56, address 0x6ea080, next address 0x6ea010, dis -112
    memory require 60, allocated 72, address 0x6ea0c0, next address 0x6ea010, dis -176
    memory require 64, allocated 72, address 0x6ea0c0, next address 0x6ea010, dis -176
    memory require 70, allocated 72, address 0x6ea0c0, next address 0x6ea010, dis -176
    memory require 72, allocated 72, address 0x6ea0c0, next address 0x6ea010, dis -176
    memory require 73, allocated 88, address 0x6ea110, next address 0x6ea010, dis -256
    -----------Large bin-------------
    memory require 1024, allocated 1032, address 0x6ea010, next address 0x6ea420, dis 1040
    memory require 102400, allocated 102408, address 0x6ea010, next address 0x703020, dis 102416
    memory require 131072, allocated 131080, address 0x6ea010, next address 0x70a020, dis 131088
    memory require 262144, allocated 266224, address 0x7f0fc1283010, next address 0x6ea010, dis -139705634623488
    memory require 524288, allocated 528368, address 0x7f0fc1243010, next address 0x6ea010, dis -139705634361344
    memory require 1048576, allocated 1052656, address 0x7f0fc11c3010, next address 0x6ea010, dis -139705633837056
    

When require memory size less than 24, use fastbin to allocate memory;
When require size large than 24, use smallbin

Reference

performance optimization of C++

Tools for detect time killer

Tips for Performance Improvement Code Optimization

memory allocate on stack or heap

Allocate memory on stack is more faster then heap cause of different architecture.
The heap is a far more complicated data structure than the stack.

Ref:

vector vs array

Use the right container

Some tips when using C++

1
2
3
4
5
6
7
class Foo
{
const BigObject & bar();
};

BigObject obj = foo.bar(); // OOPS! This creates a copy!
const BigOject &obj = foo.bar(); // does not create a copy

some books

  • Effective C++
  • More Effective C++
  • Effective STL
  • C++ Coding Standards
  • Efficient C++: Performance Programming Techniques

Know some compile and linker options

  • gcc

Reference

check pow overflow

Source code

// Create by matrix207 2016-03-09
// g++ -o t check-pow-overflow.cc

#include <iostream>
#include <typeinfo>
#include <cmath>
#include <limits>

/*
 * Check if pow overflow for type T (int,float,long,double)
 * a^b <= m  <=> log(a^b) <= log(m) <=> b*log(a) <= log(m) <=> b <= log(m)/log(a)
 * @param a
 *     base number
 * @param b
 *     exponent number
 * @return
 *     1 if overflow, otherwise 0
 */
template<typename T1, typename T2>
int check_pow(T1 a, T2 b)
{
    int ret = 0;
    // i:int, f:float, d:double, l:long
    std::cout << "Type: " << typeid(a).name() << "," << typeid(b).name() << " ";
    double max_a = std::log(std::numeric_limits<T1>::max());
    double max_b = std::log(std::numeric_limits<T2>::max());
    double max_max = max_a < max_b ? max_b : max_a;
    if (b * std::log(a) < max_max) {
        double c = std::pow(a, b);
        std::cout << a << "^" << b << "=" << c << std::endl;
    } else {
        std::cout << a << "^" << b << " overflow" << std::endl;
        ret = 1;
    }
    return ret;
}

int main(int argc, char* argv[])
{
    std::cout << "\n>>> Test int type <<<" << std::endl;
    check_pow(25, 1);
    check_pow(25, 10);
    check_pow(25, 100);
    check_pow(25, 1000);

    std::cout << "\n>>> Test long type <<<" << std::endl;
    check_pow(25L, 1L);
    check_pow(25L, 10L);
    check_pow(25L, 100L);
    check_pow(25L, 1000L);

    std::cout << "\n>>> Test float type <<<" << std::endl;
    check_pow(25.3f, 1.0f);
    check_pow(25.3f, 10.0f);
    check_pow(25.3f, 100.0f);
    check_pow(25.3f, 1000.0f);

    std::cout << "\n>>> Test double type <<<" << std::endl;
    check_pow(25.3, 1.0);
    check_pow(25.3, 10.0);
    check_pow(25.3, 100.0);
    check_pow(25.3, 1000.0);

    std::cout << "\n>>> Test mix type <<<" << std::endl;
    check_pow(25, 10.0); // int, double
    check_pow(25, 100.0); // int, double
    check_pow(25, 1000.0); // int, double
    check_pow(25.0f, 10.0); // float, double
    check_pow(25.0f, 100.0); // float, double
    check_pow(25.0f, 1000.0); // float, double

    std::cout << "\n>>> Test others <<<" << std::endl;
    check_pow(0, 100);
    check_pow(0, -2);
    check_pow(-1, -2);
    check_pow(-1, -20);
    check_pow(25, -20);

    return 0;
}

Test

[dennis@localhost code]$ g++ -o t check-pow-overflow.cc
[dennis@localhost code]$ ./t

>>> Test int type <<<
Type: i,i 25^1=25
Type: i,i 25^10 overflow
Type: i,i 25^100 overflow
Type: i,i 25^1000 overflow

>>> Test long type <<<
Type: l,l 25^1=25
Type: l,l 25^10=9.53674e+13
Type: l,l 25^100 overflow
Type: l,l 25^1000 overflow

>>> Test float type <<<
Type: f,f 25.3^1=25.3
Type: f,f 25.3^10=1.0745e+14
Type: f,f 25.3^100 overflow
Type: f,f 25.3^1000 overflow

>>> Test double type <<<
Type: d,d 25.3^1=25.3
Type: d,d 25.3^10=1.0745e+14
Type: d,d 25.3^100=2.05141e+140
Type: d,d 25.3^1000 overflow

>>> Test mix type <<<
Type: i,d 25^10=9.53674e+13
Type: i,d 25^100=6.22302e+139
Type: i,d 25^1000 overflow
Type: f,d 25^10=9.53674e+13
Type: f,d 25^100=6.22302e+139
Type: f,d 25^1000 overflow

>>> Test other <<<
Type: i,i 0^100=0
Type: i,i 0^-2 overflow
Type: i,i -1^-2 overflow
Type: i,i -1^-20 overflow
Type: i,i 25^-20=1.09951e-28

Reference

stack trace when program crash

Source

#include <stdio.h>
#include <execinfo.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>

void handler(int sig) {
    void *array[10];
    size_t size;

    // get void*'s for all entries on the stack
    size = backtrace(array, 10);

    // print out all the frames to stderr
    fprintf(stderr, "Error: signal %d:\n", sig);
    backtrace_symbols_fd(array, size, STDERR_FILENO);
    exit(1);
}

void baz() {
    int *foo = (int*)-1; // make a bad pointer
    printf("%d\n", *foo);       // causes segfault
}

void bar() { baz(); }
void foo() { bar(); }

int main(int argc, char **argv) {
    signal(SIGSEGV, handler);   // install our handler
    foo(); // this will call foo, bar, and baz.  baz segfaults.
}

Compile and test

[dennis@localhost code]$ gcc -g -rdynamic -o t stacktrace.c
[dennis@localhost code]$ ./t
Error: signal 11:
./t(handler+0x1c)[0x400a32]
/lib64/libc.so.6(+0x34960)[0x7fa03d30d960]
./t(baz+0x14)[0x400a8b]
./t(bar+0xe)[0x400aae]
./t(foo+0xe)[0x400abe]
./t(main+0x28)[0x400ae8]
/lib64/libc.so.6(__libc_start_main+0xf0)[0x7fa03d2f8fe0]
./t[0x400949]

Reference

c++

Books

  • C++FAQS
  • Junior
    • (C++11)C++11 - 维基百科,自由的百科全书
    • (C++11)深入理解C++11:C++ 11新特性解析与应用 迷你
    • [C++标准程序库–自修教程与参考手册]
    • [C++程序设计原理与实践]
    • [C++程序设计语言 特别版]
    • [C++编程惯用法——高级程序员常用方法和技巧]
    • [C++编程规范-101条规则准则与最佳实践]
    • [C++语言的设计和演化]
    • [C++释难解惑]
    • [C和C++安全编码(中文版)]
    • [Effective C++中文版(第三版)]
    • [More Effective C++ 中文版]
    • [[Effective STL中文版:50条有效使用STL的经验]]
    • [Exceptional C++ Style(Herb Sutter).中文版]
    • [Exceptional C++ 中文版]
    • [More Exceptional C++(中文版)]
    • [From C++ to Objective-C-english]
    • [From C++ to Objective-C-中文版]
    • [Linux C编程一站式学习6.14–宋劲衫]
    • [从缺陷中学习C、C++]
    • [你必须知道的222个C++语言问题.范立锋.扫描版]
    • [标准C++库函数参考]
    • [深入学习:GNU C++ for Linux 编程技术]
    • [编写高质量代码 改善C++程序的150个建 议.李健.扫描版]
  • C/C++进阶
    • [Accelerated C++中文版 ]
    • [Advanced c++ Programming Styles and Idioms中文版]
    • [C++ API设计–英文版]
    • [C++ Templates中文版]
    • C++ 工程实践经验谈–陈硕
    • [C++ API设计]
    • [C++代码设计与重用]
    • [C++标准库——自学教程与参考手册(第2版)英文版]
    • [C++沉思录(Ruminations on C++)中文第2版]
    • [C++程序设计]
    • [C++设计新思维(Modern_C++_Design)]
    • [大规模C++程序设计]
    • [模板编程与OO编程范型–混搭]
    • [深度探索C++对象模型]
    • [高质量C++/C编程指南]
    • [Imperfect C++]
    • [C++ 并发编程指南]

Projects

  • 1.leveldb
    • Google出品,遵循Google C++编码规范
    • 作者是Jeff Dean大神
    • 涉及查找、缓存、文件读写、多线程、跨平台等诸多常见问题
    • 最新版本1.15.0代码量也不到2万行
    • 基础的key-value数据库,广泛用于Google内部和许多开源项目
  • Google Test
  • Protocol Buffers
  • 2.llvm
  • 2.muduo

Lambda

resource manager

  • Implement ScopeGuard

  • Sample code:

    // TODO: not work
    // g++ -o t -std=c++11 c++11.cc
    #include <stdio.h>
    #include <vector>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    
    #define TT_HERE() {std::cout << __FUNCTION__ << ":" << __LINE__ << std::endl;}
    #define TT_PRINT_MSG(x) {std::cout << __LINE__ << ":" << x << std::endl;}
    
    class ScopeGuard
    {
    public:
        explicit ScopeGuard(std::function<void()> onExitScope)
            : onExitScope_(onExitScope), dismissed_(false)
        { }
    
        ~ScopeGuard()
        {
            TT_HERE();
            if(!dismissed_)
            {
                onExitScope_();
            }
        }
    
        void Dismiss()
        {
            dismissed_ = true;
        }
    
    private:
        std::function<void()> onExitScope_;
        bool dismissed_;
    
    private: // noncopyable
        ScopeGuard(ScopeGuard const&);
        ScopeGuard& operator=(ScopeGuard const&);
    };
    
    #define SCOPEGUARD_LINENAME_CAT(name, line) name##line
    #define SCOPEGUARD_LINENAME(name, line) SCOPEGUARD_LINENAME_CAT(name, line)
    
    #define ON_SCOPE_EXIT(callback) ScopeGuard SCOPEGUARD_LINENAME(EXIT, __LINE__)(callback)
    
    class A
    {
    public:
        A () { TT_HERE(); }
        ~A () { TT_HERE(); }
    };
    
    void release()
    {
        std::cout << "do release" << std::endl;
    }
    
    class B
    {
    public:
        B () {
            TT_HERE();
        }
        ~B () { TT_HERE(); }
        void Fun1() {
            A a;
            std::cout << "do something in Fun1" << std::endl;
            std::cout << "throw exception" << std::endl;
            throw;
            release;
        }
    };
    
    class C
    {
    public:
        C () {
            TT_HERE();
        }
        ~C () { TT_HERE(); }
        void Fun1() {
            A a;
            ON_SCOPE_EXIT( [&] { release();} );
            std::cout << "do something in Fun1" << std::endl;
            std::cout << "throw exception" << std::endl;
            throw;
        }
    };
    
    void Test1()
    {
        std::vector<int> v;
        v.push_back(1);
        v.push_back(2);
        v.push_back(3);
    
        std::for_each(std::begin(v), std::end(v), [](int n) {std::cout << n << std::endl;});
    
        auto is_odd = [](int n) {return n%2==1;};
        auto pos = std::find_if(std::begin(v), std::end(v), is_odd);
        if(pos != std::end(v))
            std::cout << *pos << std::endl;
    }
    
    int main()
    {
        std::cout << "------------------------" << std::endl;
        B b;
        //b.Fun1();
        std::cout << "------------------------" << std::endl;
        C c;
        c.Fun1();
        std::cout << "------------------------" << std::endl;
    
        return 0;
    }
    

Error handle

  • Target:
    • easy to use
    • more error message
    • be strong
  • Error information collection

    • information include: error, location and context
    • ENSURE(0 <= index && index < v.size())(index)(v.size());

      Failed: 0 <= index && index < v.size()  (error)
      File: xxx.cpp Line: 123                 (location)
      Context Variables:                      (context)
          index = 12345
          v.size() = 100
      
    • support multiple express (ENSURE(expr)(var1)(var2)(var3))

    • static_assert(std::is_same<decltype(expr), bool>::value, "ENSURE(expr) can only be used on bool expression");
  • Implementation sample

    // Create by matrix207 2016-03-08
    // compile: g++ -o t -std=c++0x ensure.cc
    // expand macro with : g++ -E -P -std=c++0x ensure.cc
    #include <exception>
    #include <iostream>
    #include <sstream>
    
    class MyException
    {
    public:
        MyException(const char *exp, const char *file, int line)
            : SMART_ASSERT_A (*this),
              SMART_ASSERT_B (*this)
        {
            std::ostringstream so;
            so << "Ensure failed : " << '\n'
               << '\t' << "Expression : " << exp << '\n'
               << '\t' << "Location : " << file << ':' << line << '\n';
            m_what += so.str();
        }
        template<typename T>
        MyException& printVariable(const char* name, T v)
        {
            std::ostringstream so;
            so << '\t' << name << " : " << v << '\n';
            m_what += so.str();
            return *this;
        }
        MyException& err(int error)
        {
            std::ostringstream so;
            so << '\t' << "Error : " << error << '\n';
            m_what += so.str();
            return *this;
        }
        MyException& msg(const char* msg)
        {
            std::ostringstream so;
            so << '\t' << "Message : " << msg << '\n';
            m_what += so.str();
            return *this;
        }
        const char *what() const throw ()
        {
            return m_what.c_str();
        }
        MyException& SMART_ASSERT_A;
        MyException& SMART_ASSERT_B;
    private:
        mutable std::string m_what;
    };
    
    #define SMART_ASSERT_A(x) SMART_ASSERT_AB(x, B)
    #define SMART_ASSERT_B(x) SMART_ASSERT_AB(x, A)
    #define SMART_ASSERT_AB(x,next) \
        SMART_ASSERT_A.printVariable(#x,(x)).SMART_ASSERT_ ## next
    
    #define MY_ENSURE(expr) \
        if (expr); else throw MyException(#expr,__FILE__,__LINE__).SMART_ASSERT_A
    
    int main()
    {
        try
        {
            int a = 2;
            MY_ENSURE(a > 3)(a).err(10001).msg("error occur!");
        }
        catch (const MyException& e)
        {
            std::cout << "catch exception:\n" << e.what() << std::endl;
        }
        return 0;
    }
    
  • test

    [dennis@localhost code]$ g++ -g -o t -std=c++0x ensure.cc
    [dennis@localhost code]$ ./t
    catch exception:
    Ensure failed : 
        Expression : a > 3
        Location : ensure.cc:67
        a : 2
        Error : 10001
        Message : error occur!
    

Reference