如何知道gcc/g++ 的默认C++版本

C++在C++ 11之后在保持向后兼容的情况下,语法增强了非常多,变化很大。得益于Move语义,和一些标准库的改进(如std::list的size()函数在C++11之前是O(n)的复杂度,从C++11开始变成常数复杂度)。一些旧C++代码即使什么改动也不做,只需要在新的C++标准下编译,也能获得性能提升。一般要给g++开启C++11需要用 -std=c++11,开启C++17则是 -std=c++17。那么,如果不添加这些选项,gcc/g++默认使用的C++版本号是什么呢?

如果你的gcc/g++版本号大于4.7的话,可以用如下命令获得默认c++版本。

kamus@shyyp.net:~g++ --version | head -1
g++ (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
kamus@shyyp.net:~ g++ -dM -E -x c++  /dev/null | grep -F __cplusplus
#define __cplusplus 201402L
kamus@shyyp.net:~$ gcc -dM -E -x c++  /dev/null | grep -F __cplusplus    #其实用gcc也可以
#define __cplusplus 201402L

如上所示,我的g++版本是9.3.0。它的默认C++版本是C++14。
这是我家用的电脑。我在公司的机器上运行结果如下:

kamuszhou@centos ~ g++ --version | head -1
g++ (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4
kamuszhou@centos~ g++ -dM -E -x c++  /dev/null | grep -F __cplusplus
#define __cplusplus 199711L

如上所示,老版的g++ 4.8.4用的默认C++版本还是c++98

再解释一下这里用到的gcc/g++的选项, 这里-dM的意思是:

Instead of the normal output, generate a list of ‘#define’ directives for all the macros defined during the execution of the preprocessor, including predefined macros. This gives you a way of finding out what is predefined in your version of the preprocessor.

对所有宏,包括预定义的宏,在预编译阶段输出一系列的#define。

-E的意思是,做完预编译后即退出,不执行真正的编译。
-x c++表示使用C++语言。

用Range Adaptor,废弃replace_copy_if之类的函数

看看replace_copy_if的一个简单的例子:

std::vector<int> vec;

boost::replace_copy_if(rng, std::back_inserter(vec), pred, new_value);

对于这种写法,如果使用Range Adaptor的话,则可以写成:

std::vector<int> vec;

boost::push_back(vec, rng | boost::adaptors::replaced_if(pred, new_value));

第二种写法有什么好处呢,

1. 更高效率。因为std::back_inserter有额外的内存分配开销。

2. 更灵活。因为第二种写法可以应用更多的适配器,比如: boost::push_back(vec, rng | boost::adaptors::replaced_if(pred, new_value) | boost::adaptors::reversed);

3. 更安全。因为第二种写法没有用unbounded output iterator。

boost::io_service的poll_one和run_one有什么区别

boost::io_service的poll_one会立即返回(non-blocking),不管有没有已经被触发的处理函数(ready handler)。

而run_one有可能阻塞。如果还没有被触发的处理函数,run_one会阻塞到有一个handler被调用为止。

更多资料: http://think-async.com/

呃。这篇日志也太短了!!!

BOOST库真是个好东西啊~~好多写法很有现代脚本语言的taste。~~而且,那么丰富的库让生产效率大大提高了。

 

copyright ykyi.net

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

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