boost 学习笔记 10:设计模式

设计模式是一个面向对象的通用解决方案,是一套被反复使用,多数人知晓的代码设计经验总结。

一般分为:创建型模式、机构型模式和行为模式

创建型模型

抽象工厂 Abstract Factory

提供统一的创建接口。

生成器 Builder

将复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。

工厂方法

定义接口用于创建对象。

原型 Prototype

原型模式使用类的实例通过拷贝的方式创建对象,具体的拷贝行为可以定制。最常见的用法为类实现一个 clone() 成员函数,这个函数创建一个与原型相同或者相似的新对象。

单件 Singleton

运行时,类有且仅有一个实例。

结构性模型

如何组合类或者对象,更而形成更大更有用的新对象。

适配器 Adapter

把一个类的接口转换成另一个接口,在不改变原有代码的基础上复用原代码。

桥接 Bridge

将抽象部分与实现部分分离,使它们都可以独立的变化。

组合 Composite

将小对象组合成树形结构。

装饰 Decorator

运行时动态地给对象增加功能。

外观 Facade

为系统中大量对象提供一个一致的对外接口,简化系统使用。

享元 Flyweight

使用共享的方式节约内存的使用

代理 Proxy

它的意图不是改变接口插入新系统(适配),也不是为对象增加职责(装饰),而是要控制对象。

智能指针库,利用代理模式将原始指针包装,代理原始指针的职能。

行为模式

职责链 Chain of Responsibility

把对象连成一条链,使链上的每个对象都有机会处理请求。

命令 Command

将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化。

解释器 Interpreter

给定一个语言, 定义它的文法的一种表示,并定义一个解释器, 该解释器使用该表示来解释语言中的句子。

迭代器 Iterator

提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。

中介者 Mediator

包装了一系列对象相互作用的方式,使得这些对象不必相互明显作用,从而使它们可以松散偶合。当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用,保证这些作用可以彼此独立的变化。

备忘录 Memento

备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捉住,并外部化,存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。

观察者 Observer

定义对象间一对多的联系,当一个对象的状态发生变化时,所有与它有联系的观察者对象都会得到通知。

状态 State

允许对象在状态发生变化时行为也同时发生改变。

策略 Strategy

封装不同的“算法”,使它们可以在运行时相互替换。

模板 Template method

模板方法模式准备一个抽象类,将部分逻辑以具体方法及具体构造子类的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。先构建一个顶级逻辑框架,而将逻辑的细节留给具体的子类去实现。

访问者 Visitor

分离类的内部元素和访问它们的操作,可以在不改变内部元素的情况下增加作用于它们的新操作。

其他模式

空对象

用于返回无意义的对象时,它可以承担处理null的责任。

包装外观

通过外观的包装,使应用程序只能看到外观对象,而不会看到具体的细节对象,这样无疑会降低应用程序的复杂度,并且提高了程序的可维护性。

前摄器模式 Proactor

用于为异步事件多路分离和分派处理器的对象行为模式


2016-01-18 boost , C++

国家博物院一日游

说了很久想去国家博物院,只是迟迟没有动脚,终于熬到今天。本不是旅游旺季,早上9点出门到那边依然能够领到票进去,排队人数也不是很多,几乎就是去了拿票直接进。如果想要预约门票的话,提早电话或者网上预定,可参见官网文章

去的时候没有查攻略,也没有看任何文章,进到博物馆才发现那边这么大,一时间竟然不知道从那边逛起,幸而查了一眼马蜂窝,看到有人建议到地下一层从《古代中国》开始看。于是开始一段非常漫长的游览史,不是知道是因为走得太慢还是看的太认真,当走到“三国魏晋南北朝”开始已经开始寻找座位想要快速结束这段旅程了。而此后一遍又一遍的感慨中国历史太长,沉浸其中容易无法自拔。

参观的时候没有导游,所以大部分时间就是在读文物的介绍,然后自己维基百科查看,夏商周时候那些青铜器皿,几乎没有知道作用的,于是和小伙伴开始了异想天开,这是洗澡用的,这是喝酒用的,等等,不过倒也知道了一些知识:

  • ”匜“,拼音yí,是先秦的礼器,客人洗手之用。当时还在讨论,如果是,盛水,洗手器,为什么不写成半包围,中间加个手字,多形象
  • 瓦当,已经忘记了在哪个朝代看到的了,后来查看维基才知道,发明于战国时期的鲁班。是屋檐最前面的圆形瓦片,古人会在上面雕刻图案或者神兽。
  • 知道了三国中的魏国并不是曹操建立的,而是他儿子废了汉,看三国的时候没注意呢。
  • 知道了竹林七贤,除了嵇康,阮籍之外多记住了一个刘伶,其他的还是没记住
  • 知道了原来王守仁就是王阳明,他的书法还很不错

后来的后来真的没怎么看了,几乎都是快速浏览过,就这样快速的走过,光是看了一个到1912年的《古代中国》,走出展厅就已经到了下午,后来休息了一下,又粗粗的看了书法展,国博建筑概览就匆匆过去了,很多展厅也没去看,总之以后有机会再过去看看吧。以后有了小孩,应该做好充分的准备工作再去看看,回来之后看到维基上列举的一些国家级文物,印象是有的,只是当时也没有仔细的看,四羊方尊,金缕玉衣,等等当时历史教科书中存在的图片展现到眼前是还是会激动一下的。只是后来倦于拍照片,回来整理也就只几张。

给后人的参考,其之前可以大概的浏览这个维基页面,在其中的古代中国中,列举了一些文物,有一些还是很值得一看的。比如远古时期的”人面鱼纹彩陶盆“,”玉琮“等等;夏商周的青铜器;秦汉的兵马俑,石刻;到后期的瓷器等等。

人面鱼纹彩陶盆 人面鱼纹彩陶盆

大禹治水 大禹治水图

四羊方尊 著名的四羊方尊

金边玉杯 金边玉杯,得此一杯,此生足矣

金制头饰 金制头饰,匆匆路过,突然看到这个饰品,太美了。

可爱的神兽 可爱的神兽,没想到古人也是挺萌的嘛

又一只萌萌的神兽 又一只萌萌的神兽

说不上名字的青铜器 说不上名字的青铜器,已经忘了他叫什么了,应该也是尊吧。

请工作人员不要这么摆设啊,会吓死人的 最后!!!请工作人员不要这么摆设啊,会吓死人的


2016-01-17 博物院 , travel , beijing , 游记 , 经验总结

boost 学习笔记 9:并发编程

Boost中有两个用于并发编程的组件。首先是thead库:它为C++增加了可移植的线程处理能力。然后是一个用于同步和异步IO操作的功能强大的库——asio,它使用了前摄器模式,可以处理串口,网络通信,而且有望成为C++标准底层通信库。

互斥量是一种用于线程同步的手段,它可以在线程编程中防止多个线程同时操作共享资源(或称临界区)。一旦一个线程锁定了互斥量,那么其他线程必须等待他解锁互斥量才能在访问共享资源。thead提供了7中互斥量类型(实际只有五种):

  • mutex 独占式互斥量
  • try-mutex mutex 同义词
  • timed_mutex 独占式互斥量,提供超时锁定功能
  • recursive_mutex 递归式互斥量,可以多次锁定,相应也要多次解锁
  • recursive_try_mutex recursive_mutex 同义词
  • recursive_time_mutex 递归式互斥量,基本功能同 recursive_mutex ,提供超时锁定功能
  • shared_mutex multi-reader/single-writer 型共享互斥量 读写锁

mac下使用 boost thread 需要将 libboost_thread.dylib libboost_thread-mt.dylib lib boost-system.dylib 加入到工程,链接进工程。

具体用法:

#include <iostream>
#include <string>
#include <boost/assign.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/assign.hpp>
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/ref.hpp>
#include <boost/bind.hpp>
using namespace boost;
using namespace std;

#define BOOST_DATE_TIME_SOURCE
#define BOOST_THREAD_NO_LIB

// 模板类配合模板参数提供不同范围的计数,提供隐式类型转换操作
// 在多线程环境下安全计数
template <typename T>
class basic_atom: noncopyable {
private:
    T n;
    typedef boost::mutex mutex_t;
    mutex_t mu;

public:
    basic_atom(T x = T()):n(x) {}
    T operator++(){
        mutex_t::scoped_lock lock(mu);
        return ++n;
    }
//    T operator=(const T _n){
//        mutex_t::scoped_lock lock(mu);
//        n = _n;
//        return _n;
//    }
    operator T()    {return n;}
};

boost::mutex io_mu;

typedef basic_atom<int> atom_int;

void printing(atom_int& x, const string& str){
    for (int i = 0;  i < 5; ++i) {
        boost::mutex::scoped_lock lock(io_mu);
        cout << str << ++x <<endl;
    }
}

void to_interrupt(atom_int& x, const string& str){
    try {
        for (int i = 0;  i < 5; ++i) {
            this_thread::sleep(posix_time::seconds(1));
            boost::mutex::scoped_lock lock(io_mu);
            cout << str << ++x <<endl;
        }
    } catch (thread_interrupted& ) {
        cout << "thread_interrupted" <<endl;
    }
}

int main(int argc, const char * argv[]) {

    cout << "start" <<endl;
    this_thread::sleep(posix_time::seconds(2));
    cout << "sleep 2 seconds" <<endl;

    boost::mutex mu;
    try {
        mu.lock();
        cout << "do some operations" << endl;
        mu.unlock();
    } catch (...) {
        mu.unlock();
    }

    boost::mutex mu1;
    boost::mutex::scoped_lock lock(mu1);
    cout << "some operations" <<endl;

    atom_int x;

    thread t1(printing, boost::ref(x), "hello");

//    this_thread::sleep(posix_time::seconds(2));

    // join & timed_join
    if (t1.joinable()) {
        t1.join();          // 等待t1 线程结束再返回,不管执行多长时间
    }

    thread t2(printing, boost::ref(x), "boost");
    t2.timed_join(posix_time::seconds(1));      // 最多等待1秒返回

    thread t(to_interrupt, boost::ref(x), "interrupt");
    this_thread::sleep(posix_time::seconds(4));
    t.interrupt();
    t.join();

    return 0;
}

asio

Boost.Asio是一个跨平台的、主要用于网络和其他一些底层输入/输出编程的C++库。以下代码实现一个简单的tcp服务,访问http://localhost:6688可得到字符.

#include <iostream>
#include <string>
#include <boost/assign.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/assign.hpp>
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/asio.hpp>
using namespace boost;
using namespace std;

int main(int argc, const char * argv[]) {
    using namespace boost::asio;

    try {
        io_service ios;

        ip::tcp::acceptor acceptor(ios, ip::tcp::endpoint(ip::tcp::v4(), 6688));
        cout << acceptor.local_endpoint().address() << endl;

        while (true) {
            ip::tcp::socket sock(ios);
            acceptor.accept(sock);

            cout << "client:" ;
            cout << sock.remote_endpoint().address() << endl;
            sock.write_some(buffer("hello asio"));
        }
    } catch (std::exception& e) {
        cout << e.what() << endl;
    }

    return 0;
}

更多 boost.asio 相关内容查看C++ 网络编程


2016-01-16 boost , C++

boost 学习笔记 10:Python

项目中需要将C++的程序暴露给网络使用,我也不想使用C++来用网络编程,就想到可以使用Python来解决Web端,然后将 C++ 的接口暴露给 Python 。于是在寻求解决方案的时候找到了 boost.python 库。

boost 中的 Python 库支持在 Python 和 C++ 之间的自由转换,包括 C++ 到 Python 的类型转换,默认参数,关键字参数,引用,指针等等。boost.python 库可以让 Python 轻易地调用 C++ 编写的模块,也可以很容易地在 C++ 中调用 Python 。

使用

C++ 文件中需要包含头文件

#include <boost/python.hpp>
using namespace boost::python;

还需要在链接的时候,加入 -lboost_python

以下操作借助Linux下g++完成,Windows可能需要借助其他工具,导出C++函数具体实现:

hello.cpp

char const* greet()
{
    return "hello, world";
}

#include <boost/python.hpp>

BOOST_PYTHON_MODULE(hello)			// Python 模块开始
{
    using namespace boost::python;		// 打开命名空间
    def("greet", greet);
}

Makefile

PYTHON_VERSION = 2.7
PYTHON_INCLUDE = /usr/include/python$(PYTHON_VERSION)

# location of the Boost Python include files and library
#  
BOOST_INC = /usr/local/include
BOOST_LIB = /usr/local/lib

# compile mesh classes
TARGET = hello

$(TARGET).so: $(TARGET).o
    g++ -shared $(TARGET).o -L$(BOOST_LIB) -lboost_python -L/usr/lib/python$(PYTHON_VERSION)/config -lpython$(PYTHON_VERSION) -o $(TARGET).so

$(TARGET).o: $(TARGET).cpp
    g++ -I$(PYTHON_INCLUDE) -I$(BOOST_INC) -fPIC -c $(TARGET).cpp

clean:
    rm *.so *.o

hello.py

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import hello
print hello.greet()

输出: hello, world

注意将 python, boost 所在目录 include 进去,在链接时加上 -lboost_python -lpython2.7 并 include python 和 boost目录。

Demo 地址GitLab : https://gitlab.com/einverne/boost_test/


2016-01-16 boost , C++

删除社交账号状态

这两天陆陆续续通过一些插件脚本删除了一些社交网站数据。年轻的时候发过一些无聊的状态,然后很久以后都没有登陆过的一些账号,倒不如关了的好,自此以后墙外只用 Google+ ,还有Blog记录一下所思所想,墙内公开内容除了豆瓣可能也没得发了,不愿生活在一个审查的制度下。虽然我可能也不会发什么敏感的内容,可谁知道什么敏感,什么不敏感呢?

facebook

Delete all facebook posts , 可以利用以下插件删除 Facebook 所有状态,包括账号内的头像等等。

Chrome Extension link

https://chrome.google.com/webstore/detail/facebook-timeline-cleaner/lfejocdlmhhkmnabbaeckmaehmgaffje

Update: 可惜了这个插件被删除了

renren

关闭账号

weibo

delete tool 删除工具 http://app.weibo.com/detail/62A7lB

批量删除weibo http://3.amfen.sinaapp.com/

删除微博评论 http://weibo333.com/

腾讯微博

设置中关闭账号

关闭QQ空间

通过以下链接申请删除QQ空间。

http://imgcache.qq.com/qzone/web/qzone_submit_close.html


2016-01-15 经验总结 , social , posts

间谍之桥 感悟

间谍之桥 Bridge of Spies 2015 影评

一名伟大的律师,成就一件伟大的人质交换。剧情7分,表演8分,娱乐7分。汤姆汉克斯的演技自然没得说,不过俄国人质的更加深入人心,虽然并不知道他的名字,但之后就再不会忘记他的名字 —- Mark Rylance 。而电影在娱乐性方面给人更多的是思考,沉浸在那段历史中,思考的是那段历史中人们做过的每一个决策。

原本以为这部影片是讲述“间谍”之间的故事,看到开场辩护时就知道被标题所骗。联系到最近的快播案,两国在司法上可谓天上地下。从1957年的《十二怒汉》开始,到这部《间谍之桥》50多年间好莱坞从未放弃探讨司法的公平性。而前半部分的辩护差点让我以为电影会从间谍故事转变成法庭辩护。幸而在后面美国侦察机被炸到苏联土地等情节,才让故事走上交换人质的主线。也让电影变得更加主旋律。

电影中最棒的两段台词:

第一段出现在CIA希望Donovan背弃律师的誓言泄露被告的信息时,Donovan告诉CIA探员的话:

I’m Irish, you’re German, but what makes us both Americans? Just one thing, one one one. The rule book. We call it the Constitution. We agree to the rules, and that’s what makes us Americans, it’s all that makes us Americans.

第二段是 Donovan和 Abel 之间的对话。

DONOVAN: You don’t seem alarmed. ABEL: Would it help?

电影剧本下载地址


2016-01-13 movie , 思考感悟 , american , action

boost 学习笔记 8:算法

对应书中第8章 算法,这一章作者介绍的很简单,只是举例使用 foreach , minmax ,其他算法都略去了。

foreach

将C++的语法扩充,使用 foreach 循环变量。

需包含头文件

#include <boost/foreach_hpp>

具体用法:

#include <iostream>
#include <string>
#include <boost/assign.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/assign.hpp>
#include <boost/foreach.hpp>
using namespace boost;
using namespace std;

int main(int argc, const char * argv[]) {

    using namespace boost::assign;
    vector<int> v = (list_of<int>(1),2,3,4,5);

    /**
     * 第一个参数 VAR 是循环变量声明 想要高效地使用序列内元素或者修改序列,需要声明使用引用
     * 第二个参数 COL 是要遍历的序列
     *
     */
    BOOST_FOREACH(int x, v){
        cout << x << "-";
    }
    cout << endl;

    string str("hello world");
    BOOST_FOREACH(char& c, str){
        cout << c << "-";
    }
    cout << endl;

    // use typeof
    BOOST_TYPEOF(*v.begin()) y;             // BOOST_AUTO(y, *v.begin())
    BOOST_FOREACH(y, v){
        cout << y << ",";
    }
    cout << endl;

    return 0;
}

minmax

在同一次操作中同时获取最大最小值。需包含头文件:

#include <boost/algorithm/minmax.hpp>
using namespace boost;

具体用法:

#include <iostream>
#include <string>
#include <boost/assign.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/assign.hpp>
#include <boost/algorithm/minmax_element.hpp>
using namespace boost;
using namespace std;

int main(int argc, const char * argv[]) {

    using namespace boost::assign;

    vector<int> v = (list_of(543), 90, 23, 42, 3, 10);

    BOOST_AUTO(x ,boost::minmax_element(v.begin(), v.end()));
    cout << "min: " << *x.first << endl;
    cout << "max: " << *x.second << endl;

    // first_min_element  找到第一个最小值
    // last_min_element 最后一个最小值

    return 0;
}

2016-01-12 boost , C++

boost 学习笔记 7:property_tree

上一篇文章boost容器中留下一个property_tree 没有学,觉得既然 boost 提供了 property_tree 这样好的工具来给C++ 解析xml和Json,必须要留有一定的篇幅来讲它。

原先项目中使用到JSON,需要使用C++解析一段返回值, JSON 格式如下:

{
  "ret": "101",
  "error": [
    {
      "errortype": "A0001",
      "errorstroke": {
        "0": "0.2",
        "1": "0.3"
      }
    },
    {
      "errortype": "A0021",
      "errorstroke": {
        "0": "0.2",
        "1": "0.3"
      }
    }
  ]
}

error 字段是一个数组,数组中的每个元素都是一个对象Object,每个Object中是一个键值对,其中 errorstroke 同样包含一个对象。我们都知道JSON只包含三种数据结构,矢量,数组和映射(参考),这样无疑给我们的解析工作带来很多遍历,这三种数据结构几乎可以将时间所有的信息包含进去。

下面就是解析这段 JSON 字符串的具体代码:(注意将JSON字符串 escape)

#include <iostream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/foreach.hpp>
#include <string>

using namespace boost::property_tree;

int main(int argc, const char * argv[]) {

    std::string str_json = "{\"ret\":\"101\",\"error\":[{\"errortype\":\"A0001\",\"errorstroke\":{\"0\":\"0.2\",\"1\":\"0.3\"}},{\"errortype\":\"A0021\",\"errorstroke\":{\"0\":\"0.2\",\"1\":\"0.3\"}}]}";

    ptree pt;                       //define property_tree object
    std::stringstream ss(str_json);
    try {
        read_json(ss, pt);          //parse json
    } catch (ptree_error & e) {
        return 1;
    }

    std::cout << pt.get<std::string>("ret") << std::endl;
    ptree errortype = pt.get_child("error");            // get_child to get errors

    // first way
    for (boost::property_tree::ptree::iterator it = errortype.begin(); it != errortype.end(); ++it) {
        std::cout << it->first;
        std::cout << it->second.get<std::string>("errortype") << std::endl;
        ptree errorstroke = it->second.get_child("errorstroke");
        for (ptree::iterator iter = errorstroke.begin(); iter != errorstroke.end(); ++iter) {
            std::string key = iter->first;
            std::cout << iter->first << std::endl;
            std::cout << iter->second.data() << std::endl;
        }
    }

    // second way: using boost foreach feature
//    BOOST_FOREACH(ptree::value_type &v, errortype){
//        ptree& childparse = v.second;
//        std::cout << childparse.get<std::string>("errortype") << std::endl;
//        ptree errorstroke = childparse.get_child("errorstroke");
//        BOOST_FOREACH(ptree::value_type& w, errorstroke){
//            std::cout << w.first << std::endl;
//            std::cout << w.second.data() << std::endl;
//        }
//    }
    return 0;
}

代码的输出:

 101
 A0001
 0
 0.2
 1
 0.3
 A0021
 0
 0.2
 1
 0.3

再换用另外一段 JSON 尝试解析,从下面这段 JSON 中能够轻易的看出 JSON 内部的结构,支持的数据结构和类型:

{
  "array": [
    1,
    2,
    3
  ],
  "boolean": true,
  "null": null,
  "number": 123,
  "object": {
    "a": "b",
    "c": "d",
    "e": "f"
  },
  "string": "Hello World"
}

具体解析代码:

#include <iostream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/foreach.hpp>
#include <string>
using namespace std;
using namespace boost::property_tree;

int main(int argc, const char * argv[]) {

    std::string str_json = "{\"array\":[1,2,3],\"boolean\":true,\"null\":null,\"number\":123,\"object\":{\"a\":\"b\",\"c\":\"d\",\"e\":\"f\"},\"string\":\"Hello World\"}";

    ptree pt;                       //define property_tree object
    std::stringstream ss(str_json);
    try {
        read_json(ss, pt);          //parse json
    } catch (ptree_error & e) {
        return 1;
    }

    ptree arraypt =pt.get_child("array");
    for (boost::property_tree::ptree::iterator it = arraypt.begin(); it != arraypt.end(); ++it) {
        cout << it->second.data() << " ";
    }
    cout << endl;

    std::cout << pt.get<bool>("boolean") << std::endl;
    std::cout << pt.get<std::string>("null") << std::endl;
    std::cout << pt.get<int>("number") << std::endl;
    std::cout << pt.get<std::string>("string") << std::endl;
    ptree opt = pt.get_child("object");

    BOOST_FOREACH(ptree::value_type &v, opt){
        cout << v.first << " : ";
        cout << v.second.data() << endl;
    }

    return 0;
}

利用 Boost property_tree 构造 JSON 字串,以下代码能够构造上面的JSON:

#include <iostream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/foreach.hpp>
#include <string>
using namespace std;
using namespace boost::property_tree;

int main(int argc, const char * argv[]) {

    std::string str_json = "{\"array\":[1,2,3],\"boolean\":true,\"null\":null,\"number\":123,\"object\":{\"a\":\"b\",\"c\":\"d\",\"e\":\"f\"},\"string\":\"Hello World\"}";

    ptree root, arr,object;
    arr.push_back(std::make_pair("","1"));
    arr.push_back(std::make_pair("","2"));
    arr.push_back(std::make_pair("","3"));

    object.put("a","b");
    object.put("c","d");
    object.put("e","f");

    root.add_child("array", arr);
    bool boolvalue = true;
    root.put("boolean",boolvalue);
    root.put("null","null");
    int num = 123;
    root.put("number",num);
    root.add_child("object",object);
    root.put("string","Hello World");

    //write_json("out.json", root);
    stringstream s;
    write_json(s, root, false);
    string out = s.str();
    cout << out ;
    return 0;
}

两个有用的JSON工具:

Boost property_tree 解析 XML 可参考这篇文章 ,解释得非常清楚。


2016-01-11 boost , C++

boost 学习笔记 6:容器

对应书中的第七章容器与数据结构。先是讲了五个容器: array , dynamic_bitset, unordered, bimap和 circular_buffer. 他们都是对标准容器的扩充。

  • array 是对 C++内建数组的简单包装
  • dynamic_bitset 可容纳任意数量的二进制位
  • unordered 实现散列容器,非二叉树实现
  • bimap 是双向 map 扩展了std::map 的内容
  • circular_buffer 是循环队列。

tuple, any 和 variant 能够容纳不同类型容器

  • tuple 是对 std::pair 的泛化
  • any和 variant 都只能容纳一个可变类型的容器。any 可以持有任何类型数据,variant 需要在编译期指定类型。

最后 multi_arrayproperty_tree 两个组件使用组合模式实现复杂的数据结构。 multi_array 是一个泛型多维容器, property_tree 出自 1.41 版,可以解析 xml, son, ini 和 info 四种格式文件,在内部构造属性树。

对容纳元素基本要求:析构函数不能抛出异常

array

数组容器,包装了 C++ 内建数组,为其提供标准 STL 容器接口,begin(), front() 等等,性能与原始数组相差不大。但是 array 功能有限,当需要可变容量数组时,还是需要借助 std::vector 或者 boost::scoped_array

array 主要缺陷:

  • 没有构造函数,不能指定大小和初值
  • 没有 push_back() 和 push_front() ,不能动态增长
  • 不能搭配插入迭代器适配器功能

需包含头文件

#include <boost/array.hpp>
using namespace boost;

具体用法:

#include <iostream>
#include <boost/array.hpp>
#include <boost/typeof/typeof.hpp>
using namespace boost;

int main(int argc, const char * argv[]) {
    // 赋值
    array<int, 5> myArray;
    myArray[1] = 2;
    myArray.front() = 1;
    myArray.back() = 5;

    // 获取指针
    int* p = myArray.c_array();
    *(p+2) = 3;

    for (array<int,5>::iterator itr = myArray.begin(); itr != myArray.end(); ++itr) {
        std::cout << *itr << std::endl;
    }

    array<int, 10> arr2;
    arr2.assign(5);
    for (BOOST_AUTO(pos, arr2.begin()); pos != arr2.end(); ++pos) {
        std::cout << *pos << ",";
    }

    // 类似数组的初始化
    array<int, 3> ar3= { 1, 2, 3 };
    array<int, 10> ar4 = {0};           // all element equal 0
    array<std::string, 5> ar5= {"first"};  // 初始化第一个元素

    return 0;
}

dynamic_bitset

C++98 标准为处理二进制提供了两个工具: vector 和 bitset. 他们各自有优缺点: vector 可以动态增长,但不能方便地进行位运算;而 bitset 则刚好相反,可以方便地对容纳的二进制做位运算,但不能动态增长。 dynamic_bitset 正好填补了两者之间的空白。

需包含如下头文件

#include <boost/dynamic_bitset.hpp>
using namespace boost;

unordered

unordered 库提供两个散列集合类 unordered_setunordered_multiset ,同样 STLport 库也提供 hash_set 和 hash_multiset. 他们接口、用法和 STL 中标准关联容器 set/multiset 相同,只是内部使用散列代替二叉树实现,因此查找复杂度由对数降为常数。

散列容器 hash container 比二叉树的存储方式可以提供更高的访问效率。boost.unordered 库提供了一个完全符合 C++ 新标准草案 TR1 的散列容器实现,包括无序集合 set 和 无序映射 map.

unordered 库提供两个散列映射类 unordered_mapunordered_multimap ,同样 STLport 中也提供了 hash_map/hash_multimap. 他们的接口、用法和 STL 中的标准关联容器 map/multimap 相同,只是内部使用散列表代替了二叉树。

#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
using namespace boost;

代码:

#include <iostream>
#include <string>
#include <boost/assign.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
using namespace boost;
using namespace std;

int main(int argc, const char * argv[]) {
    // 散列集合类
    using namespace boost::assign;
    using namespace boost::unordered;

    // 散列集合
    unordered_set<string> s = (list_of<string>("one")("two")("three"));
    s.insert("four");
    s.erase("two");
    unordered_set<string>::iterator it = s.find("one");
    s.erase(it);
    for (unordered_set<string>::iterator itr = s.begin(); itr != s.end(); ++itr) {
        cout << *itr << endl;
    }
    s.empty();


    // 关联式容器
    unordered_map<int, std::string> um = map_list_of(1,"one")(2,"two")(3,"three");
    um.insert(std::make_pair(10,"ten"));
    um[11] = "eleven";
    um[15] = "fifteen";

    std::cout << um[15] << std::endl;
    BOOST_AUTO(p, um.begin());
    for (p; p!= um.end(); ++p) {
        cout << p->first << "-" << p->second << ",";
    }
    cout << endl;

    um.erase(11);               // delete key 11
    cout << um.size() << endl;

    // stl map
    map<int, std::string> stdmap;
    // assignment
    stdmap.insert(map<int, std::string>::value_type(1, "one"));
    stdmap.insert(std::pair<int, std::string>(2, "two"));
    stdmap.insert(std::make_pair(3, "three"));
    stdmap[4] = "four";

    map<int, std::string>::iterator pos;
    for (pos = stdmap.begin(); pos != stdmap.end(); ++pos) {
        std::cout<< "key: " << pos->first << "\t"
            << "value: " << pos->second << "\n";
    }

    stdmap.erase(4);
    cout << "map size " << stdmap.size() << endl;

    return 0;
}

bimap

可以容纳两个类型的元素,类似于 C++标准提供的映射型容器 map 和 multi_map ,但是 C++标准中的关联数组,只是将一个 key 映射到一个 value, 这种关系是单向的,只能从 key 到 value 而不能反过来。因此 boost.bimap 扩展了标准库的映射型容器,提供双向映射的能力。

对于 bimap<X, Y> , bimap.let 相当于 map<X, Y> ,而 bimap.right 相当于 map<Y, X>

bimap<collection_type_of<X>, collection_type_of<Y> >

这个概念下, std::map 和 std::multi_map 的左值是一个有序的集合,而右组无任何约束,对应的 bimap 是:

bimap< set_of<X> , unconstrained_set_of<Y> > 和 bimap<multiset_of<X>, unconstrained_set_of<Y> >

bimap 定义的集合类型包括如下:

  • set_of 可以作为键值 索引,有序且唯一,视图相当于 map
  • multiset_of 可以用作键值 索引,有序不唯一 ,视图相当于 multimap
  • unordered_set_of 可以作为键值,无序且唯一,视图相当于 unordered_map
  • unordered_multiset_of 可以作为键值,无序不唯一,视图相当于 unordered_multimap
  • list_of 不能作为键值,序列集合,无对应 STL 容器
  • vector_of 不能作为键值,随机访问集合,无对应 STL 容器
  • unconstrained_set_of 不能作为键值,无任何约束关系,无对应 STL 容器

bimap 可以使用 using namespace tags; tagged类给左组和右组数据在语法层面加上“标签”。标签的定义如下:

template< class Type, class Tag>
struct tagged {
    typedef Type value_type;
    typedef Tag tag;
};

tagged<int , struct id> 表示包装了 int 类型 ,标签名字是 id.

#include <iostream>
#include <string>
#include <boost/assign.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/bimap.hpp>
#include <boost/bimap/list_of.hpp>
#include <boost/bimap/unordered_set_of.hpp>
#include <boost/bimap/multiset_of.hpp>
#include <boost/bimap/list_of.hpp>
#include <boost/bimap/vector_of.hpp>
#include <boost/bimap/unconstrained_set_of.hpp>
#include <boost/assign.hpp>
using namespace boost;
using namespace std;

template< typename T>
void print_map(T& m){
    for (BOOST_AUTO(pos, m.begin()); pos != m.end(); ++pos) {
        cout << pos->first << "<-->" << pos->second << endl;
    }
}

int main(int argc, const char * argv[]) {

    using namespace boost::bimaps;
    using namespace tags;
    // bimap
    bimap<int, string> bmap;

    bmap.left.insert(make_pair(1, "one"));

    bmap.right.insert(make_pair("two", 2));

    for (BOOST_AUTO(pos, bmap.left.begin()); pos != bmap.left.end(); ++pos) {
        cout << "left key: " << pos->first << " value: " << pos->second << endl;
    }

    // 类型集合位于名字空间 boost::bimaps, 需包含各自同名头文件,文件位于 <boost/bimap/list_of.hpp>
    // 左组是有序集合,右组是无序集合
    bimap<int, unordered_set_of< string > > bm1;

    // 左组和右组都是有序多值集合
    bimap< multiset_of<int> , multiset_of< string > > bm2;

    // 左组是无序集合,右组是一个序列,只能有左视图
    bimap< unordered_set_of<int> , list_of<string> > bm3;

    // 左组随机访问集合,右组无约束
    bimap< vector_of<int>, unconstrained_set_of< string > > bm4;

    bimap<tagged<int, struct id>, tagged<string, struct name> > bm;
    bm.by<id>().insert(make_pair(1, "Sam"));

    bm.by<name>().insert(make_pair("Tom", 2));

    print_map(bm.by<id>());

    typedef bimap<int, string> bm_t;

    using namespace boost::assign;
    bm_t bmt = assign::list_of<bm_t::relation>(1, "one")(2 , "two");

    BOOST_AUTO(pos, bmt.left.find(2));
    cout << "key: " << pos->first << "\t" << "value: "<< pos->second << endl;
    BOOST_AUTO(pos2, bmt.right.find("one"));
    cout << "key: " << pos2->first << "\t" << "value: " << pos2->second << endl;

    bmt.left.replace_key(pos, 22);
    bmt.left.replace_data(pos, "replaced two");

    print_map(bmt.left);

    return 0;
}

bimap 还有很多高级用法,等用到的时候查阅文档吧。

circular_buffer

循环缓冲区数据结构,大小固定的循环队列。固定大小的缓存容量,当新增加的元素超过缓冲区的容量时,自动将最初的元素覆盖。

tuple

tuple 元组 定义了固定数目元素的容器,其中每个元素类型都可以不相同,这与其他容器有本质的区别。

#include <iostream>
#include <string>
#include <boost/assign.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/assign.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
#include <boost/tuple/tuple_io.hpp>
using namespace boost;
using namespace std;

int main(int argc, const char * argv[]) {

    typedef boost::tuple<int, string, double> my_tuple;
    my_tuple tuple0(1,"test");
    my_tuple tuple1 = tuple0;
    my_tuple tuple2;
    tuple2 = tuple0;

    my_tuple t1 = boost::make_tuple(2,"test",100.0);
    assert(t1.get<0>() == 2);
    assert(t1.get<1>() == "test");

    // 比较
    my_tuple t2 = boost::make_tuple(3,"test",200.00);
    assert(t1 < t2);

    // io
    cout << t1 << endl;
    cout << "input tuple: example: (1 test 200.0)"<<endl;
    cin >> t1;
    cout << t1 << endl;

    using namespace boost::assign;

    vector<my_tuple> v = tuple_list_of(1, "1", 1.0)(2, "2", 2.0);
    assert(v.size() == 2);

    return 0;
}

any

特殊容器,只能容纳一个元素,但这个元素可以是任意类型—— int , double, string, STL 容器或者任意自定义类型。程序可以用 any 保存任意的数据,在任何需要的时候将它取出来,这种功能与 shared_ptr<void> 有些类似,但 any 是类型安全的。 any 不是一个模板类。

不要用 any 保存原始指针,代替用 shared_ptr 智能指针。

当 any 以指针的方式传入 any_cast() 的时候,返回的指针类型与传入的 any 对象具有相同的常量。如果 any 不持有任何对象,这两个 any_cast() 不会抛出异常,而是返回一个空指针。

#include <iostream>
#include <string>
#include <boost/assign.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/assign.hpp>
#include <boost/any.hpp>
using namespace boost;
using namespace std;

// check object type in any
template< typename T>
bool can_cast(any &a){
    return typeid(T) == a.type();
}

// get value in any
template< typename T>
T& get(any &a){                     // &  不能丢失,否则无法修改 a 的值
    BOOST_ASSERT(can_cast<T>(a));
    return *any_cast<T>(&a);
}

template< typename T>
T* get_pointer(any &a){
    BOOST_ASSERT(can_cast<T>(a));
    return any_cast<T>(&a);
}

int main(int argc, const char * argv[]) {

    any a(10);
    int n = any_cast<int>(a);       // get value return a copy of a's data : 10
    // any_cast<double>(a) 	throw bad_any_cast
    assert(n == 10);

    a = string("test");
    a = vector<vector<int> >();

    a = n;
    assert(can_cast<int>(a));
    get<int>(a) = 11;                   // Will change a value this line
    *get_pointer<int>(a) = 12;

    return 0;
}

variant

与 any 类似,是可变类型,对 C++中 union 概念增强和扩展。

需要头文件:

#include <boost/variant.hpp>
using namespace boost;

例子:

#include <iostream>
#include <string>
#include <boost/assign.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/assign.hpp>
#include <boost/variant.hpp>
using namespace boost;
using namespace std;

int main(int argc, const char * argv[]) {

    typedef variant<int, double, string> var_t;
    var_t v;                                // v == 0
    assert(v.type() == typeid(int));
    assert(v.which() == 0);

    v = "test string";                      // v -> string
    cout << *get<string>(&v) << endl;       // get()

    try {
        cout << get<double>(v) << endl;
    } catch (bad_get &) {
        cout << "bad_get" << endl;
    }

    return 0;
}

variant 与 any 的区别

variant 和 any 都可以保存多类型的变量,但是他们的使用是有区别的。

  • 都可以容纳一个可变类型的元素,但是 variant 是有界类型,类型范围由用户指定,而 any 则是无界类型,可以容纳任意的类型
  • variant 可以在编译期类型检查
  • variant 提供泛型的 vistor 方式访问内部元素

multi_array

多维数组 的高效实现。 multi_array 是递归定义的。

#include <boost/multi_array.hpp>
using namespace boost;

具体用法:

#include <iostream>
#include <string>
#include <boost/assign.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/assign.hpp>
#include <boost/array.hpp>
#include <boost/multi_array.hpp>
#include <boost/multi_array/extent_gen.hpp>
using namespace boost;
using namespace std;

int main(int argc, const char * argv[]) {

    multi_array<int, 3> ma;             // 定义三维数组
    multi_array<int, 3> ma1(extents[2][3][4]);      // 定义维度 2/ 3/ 4 的三维数组

    for (int i=0 , v= 0; i < 2; ++i) {
        for (int j =0 ; j< 3; ++j) {
            for (int k  = 0; k < 4; ++k) {
                ma1[i][j][k] = v++;
            }
        }
    }

    boost::array<size_t, 3> idx = { 0,1,2};
    ma1(idx) = 10;
    cout << ma1(idx) << endl;

    boost::array<size_t, 3> arr = { 4,3,2};
    ma1.reshape(arr);

    for (int i = 0; i< ma1.shape()[0]; ++i) {
        for (int j = 0 ; j < ma1.shape()[1]; ++j) {
            for (int k = 0 ; k < ma1.shape()[2]; ++k) {
                cout << ma1[i][j][k] << ",";
            }
        }
    }

    ma1.resize(extents[2][9][9]);           // 改变多维数组的大小

    // 创建子视图
    /**
     * (0, 1, 2, 3)
     * (4, 5, 6, 7)
     * (8, 9, 10, 11)
     */

    typedef multi_array<int, 2> ma_type;
    multi_array<int, 2> mademo(extents[3][4]);
    for (int i = 0, v = 0; i< mademo.shape()[0]; ++i) {
        for (int j = 0 ; j < mademo.shape()[1]; ++j) {
            mademo[i][j] = v++;
        }
    }
    cout << endl;

    typedef ma_type::index_range range;
    indices[range(0,2)][range(0,2)];
    /**
     * (0, 1)
     * (4, 5)
     */

    BOOST_AUTO(view, mademo[indices[range(0,2)][range(0,2)] ]);
//    ma_type::array_view<2>::type view = ma[indices[range(0,2)[range(0,2)]];

    cout << view.num_dimensions() << endl;

    // 将一维数组适配成多维数组
    // 提供了 multi_array_ref 和 const_multi_array_ref
    // 适配完不能动态增长,其他和 multi_array 完全相同
    // const_multi_array_ref 功能少一些,因为它是只读的
    int arra[12];
    for (int i = 0; i < 12; ++i) {
        arra[i] = i;
    }
    multi_array_ref<int, 2> mar(arra, extents[3][4]);

    const_multi_array_ref<int, 2> cmar(arra, extents[2][6]);
    return 0;
}

property_tree

property_tree 容器比较复杂,它是一个保存了多个属性值得树形数据结构,功能强大,可以解析 xml, ini, json 和 info 四种格式的文本数据。单独拿一篇文章来讲它好了。


2016-01-10 boost , C++

星球大战:好莱坞流水线上的标准产物加上一些情怀催化一下

我果然不是星战迷,也没有星战情怀,相比同档期电影可以一看,但是我不是很喜欢这一部。 剧情6分(标准套路,困境解决困境),表演6.5(黑人演员可圈可点,女主没什么说的,机器人没有语言没有表情却异常的生动),娱乐性8分(一分光剑一分BB8)。

星战前六部,正传三部,前传三部,稍早的时候看过了,看原力觉醒之前没有认真补课。但是我知道好莱坞成熟流水线上的电影是不会要求你必须看完前六部再来看这一部电影的,每一部完整的电影都会有其完整的剧情和完整的人物描述。回到这一部原力觉醒,可能是星战迷内心的浴火被燃烧了,从第一部到今年三四十年的时间,足够让一个从青年变成中年甚至老年,伴随星战迷成长的电影总会伴随这一系列的讨论,今天早上看票房成绩已经是影史第四,超过票房第一的阿凡达已经是板上钉钉。基于这样的环境去影院看了。

剧情

就像之前说过的那样,这一部在剧情上的设定就是好莱坞标准的剧本设定,产生新的反派,然后需要正义人士组织反抗,制定计划一步一步瓦解反派,实在没有任何需要交代的内容。我甚至在观影过程中连续两次打哈欠,这实属罕见,在以前从来没有出现过,甚至在看《刺客聂隐娘》在场有人睡着的情况下我也没有困意,而这一部看到女主发觉拥有原力,Resistance组织开始制定作战计划开始就已经注定了结局。再到爱情,亲情的设定,总觉得会产生一些问题,大战刚刚结束,公主与将军的见面,再到后面父子的见面总感觉设定上有一些故意而为之。当然这些都是一些小的问题,总体来看剧情还是有一个及格的6分。至少前半部分,已经后面的一些情节,总能够让观众一边被主人公的台词表演逗笑,一边被剧情的紧张气氛而胆战心惊。

表演

再到表演,其实也并没有什么说得,反而到时那个萌萌的机器人能让观众会心一笑,有些时候表演并不需要语言和表情,一举一动都能够看出表演的出彩,或许这也是这部电影在表演上能给我留下的唯一印象,女主,黑人男主,再到哈里森福特,并没有什么特别出彩的地方。

BB 8

娱乐

观影风向标定下的娱乐性,其实一直不大明白,娱乐到底是指那一方面,如果是指话题性,新闻性,亦或是卖萌属性的话,就像上面说得那样我会一分给光剑,这一分给的是情怀,一分给BB8,那是因为这个“球”真是太可爱了,可爱到人人都会想要拥有一台。

总之这是一部让我觉得值得票价却也提不出什么优点的电影啦。感谢导演 JJ 艾布拉姆斯,感谢哈里森福特。


2016-01-09 思考感悟 , movie

Google+

最近文章

  • Openwrt 平均负载 Openwrt 在 Luci 后台很显眼的位置有三个不断刷新的数字,其实这个数字是“平均负载”(Load Average)的意思,这是 Linux 操作系统衡量系统负载和稳定性的重要参数。
  • Openwrt 设置 在上一篇中讲了如何刷Openwrt,这一篇主要讲一些 Openwrt 的东西,以及配置相关的内容。我有一个主路由器,设置分配的局域网地址为 192.168.1.x,给内网中分配的地址也是 192.168.1.x 开头。
  • TP LINK MR12U 刷 openwrt 今天翻箱倒柜竟然找出了我的 TP-LINK MR12U,很早之前因为3G上网卡而买的便携式路由,突然脑袋一热,干嘛不试试刷个 Openwrt 呢。记得当时是没有支持的,但是一搜竟然发现了 Openwrt 有官方支持了。于是开始动手。
  • 使用 Cron 定时重启 Openwrt 路由器 最近了解了一下 Cron,也在 WinNote 上 记录了一些笔记。学习一个新命令最好的方法就是将其用于实践。于是正好在 Openwrt 路由器上跑一下。
  • 整站备份工具 Httrack HTTrack 根据官方的介绍1,是一个易用的离线浏览工具,他允许用户从万维网中离线备份某一个网站,包括建立层叠的目录,HTML,图片,以及其他文件。工具在 GPL 协议下开源。 官方网站 http://www.httrack.com/ ↩