给我一个不做C++程序员的理由

来源:互联网 发布:筑业标书软件 编辑:程序博客网 时间:2024/04/28 20:29

 我是一个C++菜鸟,一直在努力成长,希望有一天会成为C++大虾。谁知道总是受到打击。今天看到一篇老外写的文章,又被当头一棒。

一个简单的问题,给你一个数组,例如a[10],如何得到它的元素个数?

第一反应是,很简单啊,#define countof(array) (sizeof(array)/sizeof(array[0]) )

但是它的问题是,如果array是一个指针,而不是数组,那么coutof(array)的值就是1了(假定array是int*)

而且,array还有可能是一个自定义类的对象,比如下面这个类的对象,那么结果就是这个对象的大小除以p[0]的大小了(array[0]定义成返回p[0])。

class IntArray

{

private:

    int * p;

    size_t size;

public:

    int & operator [] ( size_t i );

} x;

因此我们需要更进一步的深入,看看下面这个实现

template <typename T, size_t N>

size_t countof( T array[N] )

{

    return N;

}

它可以了吗?不行!为什么?因为参数里面的N根本没有用,T array[N]被编译器视作T array*,N被直接无视了。因此这个函数根本不可能返回N。

那怎么办呢?我们接着改造吧:

template <typename T, size_t N>

size_t countof( T (&array)[N] )

{

    return N;

}

这下我们用引用代替指针做参数,编译器就知道这里一定要传一个数组进来了,指针的不要,而且数组的大小是N。因此成功返回N。

这就是我们想要的。

OK了?依然不完美!为什么?

因为这是个函数,不是宏!函数肿么了?看看下面这个例子就知道了:

int x[10];

int y[ 2*countof(x) ]; // twice as big as x

这个显然编译不能通过。因为编译器不能在编译的时候就知道数组y的大小,它没法在编译时确定函数返回值啊。

肿么办?办法就是要在编译的时候就确定返回值,进而得到N!

?还能这样?Mission Impossible?

 

一个聪明的人想出了下面的办法:

template <typename T, size_t N>

char ( &_ArraySizeHelper( T (&array)[N] ))[N]; //函数,能在编译时确定返回值的

#define countof( array ) (sizeof( _ArraySizeHelper( array ) ))//我们想要的宏

 

@#@$@%@%@%@%$%&(*^)&^)^) ==!!!!!!!

[BTW:]我横竖看了这几行代码半天,木有看懂神马意思。大虾们原谅我这个菜鸟吧!

看了老外的解释,我终于明白了:

 

char ( &_ArraySizeHelper( ... ))[N];

省略部分内容以便于理解。现在很明显了,_ArraySizeHelper是一个函数,这个函数的返回值是“((一个大小为N的)字符数组的)引用”

真够拗口的。我把所有定于都用圆括号括起来,方便理解。

上面说了,编译器可以在编译的时候就可以知道这个函数的返回值。怎么回事呢?

看看下一行代码,

我们把 _ArraySizeHelper( array ) 单独挖出来,把它暂时替换成X 

#define countof( array ) (sizeof(X))

X是_ArraySizeHelper的返回值,实际上并不需要真正调用这个函数就可以确定它的返回值X!

还记得吗?它的返回值是“((一个大小为N的)字符数组的)引用”

于是,sizeof(X) = sizeof(“((一个大小为N的)字符数组的)引用”) = N!

因此,

#define countof( array ) (sizeof( _ArraySizeHelper( array ) ))

的结果就是N。

因为它是一个宏,因此

int x[10];

int y[ 2*countof(x) ]; // twice as big as x

可以编译通过。

OK了吗?别紧张。这个实现已经在stdlib.h里面用到了,所以可以认为OK了。

终于可以松口气了!下面是stdlib.h里面的实现:

template <typename _CountofType, size_t _SizeOfArray>
char (*__countof_helper(UNALIGNED _CountofType (&_Array)[_SizeOfArray]))[_SizeOfArray];
#define _countof(_Array) sizeof(*__countof_helper(_Array))

和上面那个实现的唯一差别就是把引用换成了指针。这个函数返回值是“指向一个((大小为N的)字符数组的)指针”。

到了这里,我已经心生怨念了。看似这么简单的一个功能,为什么搞得这么复杂?

好消息是,我们可以无视这些复杂的实现,直接用_coutof 这个库里面提供的函数。但是C++和其它语言不一样的地方是,作为一个C++程序员,你有时候需要知道库函数是怎么样实现的,才能写出更好的程序。如果你不知道上面那些,你怎么知道有_coutof呢?

会不会直接在代码中用“sizeof(array)/sizeof(array[0])"呢?PHP程序员肯定不会这样做。

这是不是一个不做C++程序员的理由呢?

原创粉丝点击