[c++]模板特化与模板递归

Hello World

//比如计算斐波那契数列
template<int n>
struct Factorial{
	const static int value=Factorial<n-1>::value*n;
};
//特化终结递归,否则上面那个递归会死循环,编译时报错
template<>
struct Factorial<0>{
	const static int value=1;
};

遍历查找变长模板包中的类型

//再比如,查找Args...泛型参数的位置,
//这个例子很有意思,能把Args...一层一层拆解,很暴力,脱!!
template <int Index, class Search, class First, class... Types>
struct get_internal {
  typedef typename get_internal<Index + 1, Search, Types...>::type type;
  static constexpr int index = Index;
};

template <int Index, class Search, class... Types>
struct get_internal<Index, Search, Search, Types...> {
  typedef get_internal type;
  static constexpr int index = Index;
};

template <class T, class... Types> T get(std::tuple<Types...> tuple) {
  return std::get<get_internal<0, T, Types...>::type::index>(tuple);
}
继续阅读[c++]模板特化与模板递归

[RAAI]智能指针:scoped_ptr

#include <boost/scoped_ptr.hpp>
#include <iostream>

int main()
{
  boost::scoped_ptr<int> p{new int{1}};
  std::cout << *p << '\n';
  p.reset(new int{2});
  std::cout << *p.get() << '\n';
  p.reset();
  std::cout << std::boolalpha << static_cast<bool>(p) << '\n';
}

#include <boost/scoped_array.hpp>

int main()
{
  boost::scoped_array<int> p{new int[2]};
  *p.get() = 1;
  p[1] = 2;
  p.reset(new int[3]);
}

支持并发遍历、修改的map

问题

在游戏开发中,经常要存储大量对象,比如玩家、怪物,在增加、删除的同时,还需要遍历。在此,我们只讨论单线程并发,不考虑多线程。在多线程情况下处理这种情况,更是自找麻烦,况且效率低下。

  1. 删除、增加<=>遍历, 是矛盾的。遍历过程中新增、新删的对象,应该如何影响遍历?
  2. 遍历还有可能是并发的。如果使用了协程,这种情况出现的机率很高;就算不使用协程,还是有可能出现:那就是遍历嵌套,遍历vector的过程中,又开启了第二次遍历(有可能你调用了一个函数,这个函数启动了遍历)。
继续阅读支持并发遍历、修改的map

[c++]一边遍历一边删除

How to remove element while iterating?

使用标准模板库的时候,想过这个问题吗?可能有人说做不到,实际上时可以的。

      //q_是个普通的队列,我们检测到符合条件的元素,就删除它。
      for (auto one = q_.begin(); one != q_.end();) {
        if (!exists(one->first)) {
          one = q_.erase(one); //删除函数的返回值是关键
        } else {
          one++;
        }
      }

其实这里的关键就是erase方法的返回值,它返回的时下一个位置的iterator,如果到了末尾会返回end,注意,这里不需要++,因为已经时下一个了。

这样 ,我们一遍循环就完成了检测、删除,很高效。

跨平台c++中处理UTF字符串

  • 基本概念
  1. 跨平常用的字符集:utf-8 utf-16 utf-32
  2. 大端、小端:这时编码顺序的问题,就像说话正着说、倒着说一样,0x1234,在存储时可以存为0x1234或者0x4321,如果实际存储顺序和我们正常阅读的顺序一致,那就是大端存储,否则就是小端。只有utf8不存在大小端问题。utf16 utf32都有大小端问题,两个系统采用相同的编码,但是大小端可能不一样,那编码就不能直接通用。其实计算机中的整数、浮点数,也一样,也可以正着存、反着存,所以不同计算机、不同系统、不同语言交互时才会需要统一序列化格式。
  3. 字符集选择:如果用与存储、传输,utf8是首选,因为体积小。如果是字符串处理,首选utf-16(它的常用字符集6万多,是固定的),utf-32,固定宽度,算法简单。如果只选一个,选utf-16把,常用字符集6万,操作也方便。网页里一般都是utf8,这样网页的体积小,因为utf8里英文字符都是单字节,光这一项,体积就小很多。
  4. locale:时区,把字符串输出到控制台时,很有可能要用到这东西了,这东西需要的是什么编码,就要把自己的字符串转成什么编码输出。
  5. unicode和utf:unicode是一个不断演进的编码体系,具体到编程上,unicode编码是16位固定编码,比较老的了,现在一般不用,麻烦,搞不懂。utf(8,16,32)编码都是相对比较新、设计考量比较全面。新的开发语言、新的操作系统,现代的应用开发,一般都会采用utf编码,我们跟随潮流走,就行了。
继续阅读跨平台c++中处理UTF字符串

luajit与c执行效率简单比较

程序是我一直用来比较的一个片段:

纯c:

static void test() {
auto start = ezg::util::now();
int ret = 0;
int N = 2000000000+1;
int M = 123;
for (int i = 0; i < N; i++) {
ret = ezg_add(ret, (i % M));
ret = ret % M;
}
auto time = ezg::util::now() - start;
ezg::logger::log(std::to_string(ret));
ezg::logger::log(std::to_string(time));
}

x64 release:
log 69
log 11212(毫秒)
继续阅读luajit与c执行效率简单比较