“右值引用”不是”右值”,而是”左值”

亮瞎你的狗眼了吧~这么拗口。 !来补一下C++基础吧~~

右值引用 rvalue reference

右值 rvalue

左值 lvalue

什么是左值 lvalue呢。

本质上,左值是一个可以拿到其地址的表达式。左值lvalue里的l,本质上是locatable的缩写,因为lvalue通常可以放置于表达式的左边,于是就有了左left值的说法。

In C++, an lvalue is an expression whose address can be taken, essentially it's a locator value.

class MetaData
{
public:
	MetaData (int size, const std::string& name)
		: _name( name )
		, _size( size )
	{}

	// copy constructor
	MetaData (const MetaData& other)
		: _name( other._name )
		, _size( other._size )
	{
		cout << "copy\n";
	}

	// move constructor
	MetaData (MetaData&& other)
		: _name( other._name )
		, _size( other._size )
	{
		cout << "move\n";
	}

	std::string getName () const { return _name; }
	int getSize () const { return _size; }
private:
	std::string _name;
	int _size;
};

class ArrayWrapper
{
public:
	// default constructor produces a moderately sized array
	ArrayWrapper ()
		: _p_vals( new int[ 64 ] )
		, _metadata( 64, "ArrayWrapper" )
	{}

	ArrayWrapper (int n)
		: _p_vals( new int[ n ] )
		, _metadata( n, "ArrayWrapper" )
	{}

	// move constructor
	ArrayWrapper (ArrayWrapper&& other)
		: _p_vals( other._p_vals  )
		, _metadata( move(other._metadata ))
	{
		other._p_vals = NULL;
	}

	// copy constructor
	ArrayWrapper (const ArrayWrapper& other)
		: _p_vals( new int[ other._metadata.getSize() ] )
		, _metadata( other._metadata )
	{
		for ( int i = 0; i < _metadata.getSize(); ++i )
		{
			_p_vals[ i ] = other._p_vals[ i ];
		}
	}
	~ArrayWrapper ()
	{
		delete [] _p_vals;
	}
private:
	int *_p_vals;
	MetaData _metadata;
};

ArrayWrapper get()
{
	ArrayWrapper aw;
	return aw;
}

int main()
{
	ArrayWrapper aw(get());
	return 0;
}

这段代码中的ArrayWrapper的移动构造函数能工作吗?

错!答案是不能~ 更详细,请参考:http://www.cprogramming.com/c++11/rvalue-references-and-move-semantics-in-c++11.html

概括地讲,本质原因是因为:右值引用不是右值,而是左值。所以ArrayWrapper里的移动构造函数不会调用ArrayWrapper内嵌的MetaData的移动构造函数,而是调用它MetaData的复制构造函数。为了得到期望的行为,需要使用std::move把lvalue转换成rvalue.

 

为什么指针可以做为迭代器使用呢

写了十几年代码了,今天才知道*为什么*指针可以做为迭代器使用。

这是因为:

首先,标准库里有这样一个template,它用来得到特定迭代器的相关特性:

    namespace std {
       template <class T>
       struct iterator_traits {
           typedef typename T::value_type            value_type;
           typedef typename T::difference_type       difference_type;
           typedef typename T::iterator_category     iterator_category;
           typedef typename T::pointer               pointer;
           typedef typename T::reference             reference;
       };
   } 

而对于指针,又有这样一个模板特例化,

   namespace std {
       template <class T>
       struct iterator_traits<T*> {
           typedef T                          value_type;
           typedef ptrdiff_t                  difference_type;
           typedef random_access_iterator_tag iterator_category;
           typedef T*                         pointer;
           typedef T&                         reference;
       };
   }

这个模板特例化的意思是:对于每一个指向类型T的指针,都被定义为一个可随机访问的迭代器。

更详细的,参见文章:介绍iterator_trait http://www.codeproject.com/Articles/36530/An-Introduction-to-Iterator-Traits

copyright ykyi.net

C++准标准库boost转向github,并发布模块化boost(modular Boost)

难道是中文社区首次报道吗?我用中文搜索引擎没有搜索到modular boost的文章。

昨天想在STL的map容器上增加一个特性,即把std::map中所有的元素按照加入的先后时间用链表链接起来,以保存元素之间的时序关系。

为了这个基于std::map和std::list的新的容器能够兼容STL的算法,于是想实现stl compatible iterator。一口气读了几十页资料,发现最酷最好的方法是用boost的迭代器模板实现。纠结了很久,最终决定在我的工程中引入boost。为了获得快速开发的好处,还是加入更多的开源库吧。毕竟,如果自己造一个轮子,阅读者仍然要花时间理解你发明的轮子,还不如用已经广泛使用的轮子。况且,计划要引入boost中asio的proactor I/O模型。所以,今天就开始引入boost吧。

于是,发现boost早就发起了modular boost项目并把boost host在github.com上,如下地址:

https://github.com/boostorg

在boost的官方网站上有模块化boost的FAQ:

https://svn.boost.org/trac/boost/wiki/ModCvtFAQ

还有它的简单使用教程:

https://svn.boost.org/trac/boost/wiki/TryModBoost#InstallingModularBoost

教程上说,如果把整个module boost git clone到本地,需要花费45分钟,如果下行网速是3Mbps,而且需要占用1.5G磁盘!

我晕~~

另外FAQ上说:没办法只检出一个子库,暂时不能自动地解决依赖性问题。

原文:

Is it possible to checkout only one library and its prerequisites?

Not automatically. Automatic dependency resolution is planned for the future, but not as a part of the conversion to Git and Modular Boost.

但是,github.com/boostorg上为各个子库分别建了一个仓库喔。通过这些创库检出boost子库,不行吗?

没有兴趣去验证我的想法。

最后,我还是用最原始的方法使用boost库吧~~就是下载整个库的压缩包到我的机器上再解开。

等boost解决了检出子库时的自动依赖性检查的问题,再迁移到git submodule管理boost库。

copyright ykyi.net

怎么知道gcc搜索头文件的路径

每个C/C++程序员都知道,对于#include directive,一般,以双引号引用的头文件是程序号自定义的头文件。而用尖括号引用的头文件是系统的头文件或其它库文件。

更详细的,编译器先在当前目录找用双引号""引用的头文件,如果找不到再到系统目录找这个头文件。而对于尖括号引用的头文件,编译器就只在系统文件中搜索了。

那么,到底是在哪些目录中搜索头文件呢?

可以用cpp查看,如下:

root@vicarious:/home/kamus/projs/horoscope/boost# cpp -v
Using built-in specs.
COLLECT_GCC=cpp
Target: x86_64-linux-gnu
Thread model: posix
gcc version 4.7.2 (Debian 4.7.2-5)
COLLECT_GCC_OPTIONS='-E' '-v' '-mtune=generic' '-march=x86-64'
 /usr/lib/gcc/x86_64-linux-gnu/4.7/cc1 -E -quiet -v -imultiarch x86_64-linux-gnu - -mtune=generic -march=x86-64
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-linux-gnu/4.7/include
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/4.7/include-fixed
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.

 

一般编写makefile时给gcc指定 -I选项,-I的参数代表的目录是搜索系统头文件时使用的目录。可以试试# cpp -I/tmp -v 

/tmp目录会被添加为搜索系统头文件时的第一个目录。

如果想要添加搜索双引号""引用的头文件使用的目录呢,用 -iquote 选项指定更多的目录。

copyright ykyi.net

Linux的环境变量LD_DEBUG调试so的加载

一个稍微有经验的Linux程序员都知道使用LD_LIBRARY_PATH 来临时设置加载器搜索动态链接库so的路径顺序。但另一个不为人知的环境变量是LD_DEBUG。这个变量可以提供非常详细的加载动态链接库的信息。

 

可以把LD_DEBUG设成以下值:

export LD_DEBUG=files     # 显示库的依赖性和加载的顺序

export LD_DEBUG=bindings  # 符号绑定

export LD_DEBUG=libs   # 显示加载器查找库时使用的路径的顺序

export LD_DEBUG=versions  # 版本依赖性

export LD_DEBUG=help  # LD_DEBUG的帮助信息

 

试一下把LD_DEBUG设成以上值之一,再随便运行一个程序试试。

一个试验:

root@vicarious:/home/kamus/projs/horoscope/bins# export LD_DEBUG=libs

root@vicarious:/home/kamus/projs/horoscope/bins# vim my.conf

     24360:   find library=libm.so.6 [0]; searching

     24360:   search cache=/etc/ld.so.cache

     24360:     trying file=/lib/x86_64-linux-gnu/libm.so.6

     24360:

     24360:   find library=libtinfo.so.5 [0]; searching

     24360:   search cache=/etc/ld.so.cache

     24360:     trying file=/lib/x86_64-linux-gnu/libtinfo.so.5

     24360:

     24360:   find library=libselinux.so.1 [0]; searching

     24360:   search cache=/etc/ld.so.cache

     24360:     trying file=/lib/x86_64-linux-gnu/libselinux.so.1

     24360:

     24360:   find library=libacl.so.1 [0]; searching

     24360:   search cache=/etc/ld.so.cache

     24360:     trying file=/lib/x86_64-linux-gnu/libacl.so.1

     24360:

     24360:   find library=libgpm.so.2 [0]; searching

     24360:   search cache=/etc/ld.so.cache

     24360:     trying file=/usr/lib/x86_64-linux-gnu/libgpm.so.2

     24360:

     24360:   find library=libc.so.6 [0]; searching

     24360:   search cache=/etc/ld.so.cache

     24360:     trying file=/lib/x86_64-linux-gnu/libc.so.6

     24360:

     24360:   find library=libdl.so.2 [0]; searching

     24360:   search cache=/etc/ld.so.cache

     24360:     trying file=/lib/x86_64-linux-gnu/libdl.so.2

     24360:

     24360:   find library=libattr.so.1 [0]; searching

     24360:   search cache=/etc/ld.so.cache

     24360:     trying file=/lib/x86_64-linux-gnu/libattr.so.1

copyright ykyi.net

运行loadlib()提示attempt to call global ‘loadlib’ (a nil value)

2009年的时候用过lua,当时在windows上写金山急救箱的恶意软件库引擎。

时隔多年,又要玩一把lua. 重拾lua,在lua控制台用loadlib载入动态链接库时出错:

> loadlib("libhello.so", "*")
stdin:1: attempt to call global 'loadlib' (a nil value)
stack traceback:
    stdin:1: in main chunk
    [C]: in ?

Lua表示在全局域中没有loadlib。google后发现两种解决方案:

第一种认为这种错误是因为没有把loadlib编译进lua中,需要改makefile.如此贴的楼主所述: http://lua-users.org/lists/lua-l/2009-02/msg00463.html

第二种是在csdn上的贴子,要改lua的源文件中的一个define,实际上这种方法也是可以在makefile中define一个变量的。

不过!!!

问题其实更简单,不需要改什么makefile文件:

http://lua-users.org/lists/lua-l/2009-02/msg00466.html

lua在5.0以后,loadlib已经不在全局域中了,loadlib在package名字空间中了。

这样就好了:

package.loadlib("libhello.so", "*")

实际上,loadlib是一个底层的函数。不像require,loadlib不在path里进行查找,也不自动添加文件名后缀。这个函数在某些平台上不被支持,因为ANSI并没有要求支持动态链接库。

copyright ykyi.net

什么是0MQ或ØMQ,或ZeroMQ

ØMQ或者拼写成ZeroMQ,0MQ,是一个高性能异步消息队列库,旨在在分布式可扩展的并行程序中使用。它提供了一个消息队列,但不像面向消息的中间件,即使没有特定的消息经纪人(Message Broker),0MQ也能正常工作。

 

这个库在TCP的基础上开发,但能获得比TCP更高的性能,更不用说它提供了各种安全机制和分布式易扩展的特性。

 

0MQ的API和传统的socket很像。OMQ中的socket描述了一个,多个终端之间的多对多的连接。0MQ还有一个消息模式的概念。基本的0MQ消息模式有:

Request-reply:

用来连接一组客户端和一组服务。这个模式是一个远程过程调用RPC,和多任务分发模式。

Publish-subscribe:

用来连接一组发行端和一组接收端。这是一个数据分发模式。

Push-Pull(Pipeline)

用扇入/扇出模式连接很多结点,通常要分好几个步骤。这是一个多任务并行分布和收集的模式。

Exclusive Pair:

用排它模式连组两个socket。这其实是一个为特殊需求准备的高级底层模式。

 

每一种模式定义了一个对应的网络拓扑。Request-reply模式定义了所谓的”服务总线”,publish-subscribe定义了数据分发树,push-pull定义了并行管道。这样模式都被精心设计,使他们可以在互联网上被无限扩展。

 

不想译了,。更多内容见wikipedia。kamuszhou@qq.com 腾讯视频广告

copyright ykyi.net

Git 的M,T,D,A,U标志是什么意思

在使用git checkout , git status,或git diff files时会出现奇怪的标志。如M,T,D,A,R,U等等。

如:

# git checkout master

M     cpp-iniparser

文件cpp-iniparser前面有个M. git的这些奇怪标志是什么意思呢。

A: 增加的文件.

C: 文件的一个新拷贝.

D: 删除的一个文件.

M: 文件的内容或者mode被修改了.

R: 文件名被修改了。

T: 文件的类型被修改了。

U: 文件没有被合并(你需要完成合并才能进行提交)

X: 未知状态。(很可能是遇到git的bug了,你可以向git提交bug report)

在git diff-files的手册man git diff-files中可以查到这些标志的说明。

这些状态标志在git的源代码的diff.h文件中被定义。

copyright ykyi.net

使用Git的submodule功能管理第三方库

用Git的Submodule功能来管理代码中使用的其它库,还是满方便的。主要用到三个命令:

Git submodule add, git submodule init, git submodule update.

git submodule init to initialize your local configuration file and git submodule update to fetch all the data from that project and check out the appropriate commit listed in your superproject.

还有两个查看相关信息的命令git submodule summary,和 git submodule status.

Git的submodule功能带来的好处和坏处都很多,网上有大量的贴子反对使用git submodule。

我觉有限制地,在以下场景用git submodule管理第三方库的代码还是很不错。

1.    你使用的第三方库更新非常慢,甚至不更新,它的接口很稳定。比如:管理vim的插件们。

2.    第三方库以比较固定的周期更新。于是,过一段时间再把上游的代码拉到submodule上来。

3.    第三方库虽然更新很快,但我过一段时间才拉取上游代码也无所谓。

如果单开一个git clone管理第三方库,与自己的项目平行,当然也是可以的。但这样有个问题是,别人git clone了你的项目,还需要再git clone一次你的项目依赖的项目,并放在适当的相对路径上。而使用git submodule *时,你的项目和你依赖的库是层级关系,有条理得多。

 

还有一种方式是把第三方库的代码合并到自己的代码中。这样做的坏处是显而易见的,如果你要合并上游代码的FIX或功能加强,都非常的麻烦。大多数人是不会去做这个同步的,于是代码会被手动复制,越来越多的细微改动分散在各个不同的项目的相同/相近代码中。一片混乱….

使用Git Submodule时忽略Submodule的改动:

如果submodule中有生成新文件。在父工程(superproject)中用git status,就总会提醒你git submodule子模块有还没被跟踪的文件。

比如:一次make会生成很多.o,.dep文件。比如用git submodule管理vim插件会生成各种临时文件。你不想让git status提醒你,这多么烦人啊。

如下,git status总提醒我cpp-iniparser子模块有未跟踪的文件:

root@vicarious:/home/kamus/projs/horoscope# git status
# On branch dev
# Changes not staged for commit:
#   (use "git add <file>…" to update what will be committed)
#   (use "git checkout — <file>…" to discard changes in working directory)
#   (commit or discard the untracked or modified content in submodules)
#
#    modified:   configuration.cpp
#    modified:   configuration.h
#    modified:   cpp-iniparser (untracked content)

如何让git忽略到这个提醒呢,解决方法是编辑父工程中的.gitmodules文件。加入 ignore = dirty。如下:

[submodule “cpp-iniparser”]
    path = cpp-iniparser
    url = https://github.com/zausiu/cpp-iniparser
    ignore = dirty

 

git clone的代码里面有submodule,目录是空的。怎么clone子模块submodule的代码

对于git 1.6.5以后的版本,使用clone的–recursive,如下:

git clone –recursive git://github.com/foo/bar.git

对于老旧的git,可以使用git submodule init和git submodule update

比如:

git clone git://github.com/foo/bar.git

// 此处可以要先cd到子模块的目录,较新的git则不需要cd
git submodule init
git submodule update

git submodule status显示的HASH代码前的横杠-是什么意思

表示对应的子模块submodule还没有下载到本地。

git怎么删除一个子模块submodule

step 1: 删除.gitmodules文件中子模块的对应项

step 2: 删除.git/config文件中子模块的对应项

step 3:git rm …

git submoduler的160000什么意思?

当在包含有submodule的父工程中git commit以后,会有类似create mode 160000 submoduleName 的提示,这个160000的意思是:this is a special mode in git that basically means you're recording a commit as a commit as a directory entry rather than a subdirectory or a file.

其它有用的git submodule命令:

git diff –submodule: you can see that the submodule was updated and get a list of commits that were added to it

git submodule update –remote means: git goes into your submodules and fetch(git fetch) and update(git merge origin/master) for you.

git submodule update –remote –merge or –rebase

git submodule foreach 'git stash'; git submodule foreach 'git checkout -b featureA'

使用Git Submodules需要注意的地方:GOTCHA

1.    如果你修改了submodule的代码,那必须先commit submodule的这些修改,再到父工程(superproject)中提交commit。

2.    Git 在父工程中用git update会覆盖子模块的未提交的更新。

3.    如果手动修改了父工程目录下的.gitmodules文件,那么需要用git submodule sync来更新.git/config文件中的配置。

4. When run git submodule update, If your forget the –rebase or –merge. Git will just update the submodule to whatever is on the server and reset your project to a detached HEAD state.

copyright ykyi.net

HTTP中的HEAD方法是什么

HTTP中的HEAD方法和GET方法是一样的,除了服务器在响应HEAD方法时不充许活加消息体(message body).服务器用来回复HEAD的响应信息中,在HTTP头部中的元信息需要跟回复GET时一样。这样,一个客户就可以通过HEAD来得到某资源的源信息,而不需要把整个资源都传输一次。

HEAD方法通常被用来测试超链接的可达,和资源是否已经更新。

HEAD方法的主要应用场景是检索资源的元信息meta infomation。用getResponseHeaders()函数可以得到HTTP的头部~

copyright ykyi.net