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

亮瞎你的狗眼了吧~这么拗口。 !来补一下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 blog.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 blog.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 blog.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 blog.ykyi.net