2009年4月11日星期六

C++宏展开(zt)

转自http://www.cppblog.com/kevinlynx/archive/2008/03/19/44828.html
宏参数的prescan,
当一个宏参数被放进宏体时,这个宏参数会首先被全部展开(有例外,见下文)。当展开后的宏参数被放进宏体时,
预处理器对新展开的宏体进行第二次扫描,并继续展开。例如:
#define PARAM( x ) x
#define ADDPARAM( x ) INT_##x
PARAM( ADDPARAM( 1 ) );
因为ADDPARAM( 1 ) 是作为PARAM的宏参数,所以先将ADDPARAM( 1 )展开为INT_1,然后再将INT_1放进PARAM。

例外情况是,如果PARAM宏里对宏参数使用了#或##,那么宏参数不会被展开:
#define PARAM( x ) #x
#define ADDPARAM( x ) INT_##x
PARAM( ADDPARAM( 1 ) ); 将被展开为"ADDPARAM( 1 )"。

使用这么一个规则,可以创建一个很有趣的技术:打印出一个宏被展开后的样子,这样可以方便你分析代码:
#define TO_STRING( x ) TO_STRING1( x )
#define TO_STRING1( x ) #x
TO_STRING首先会将x全部展开(如果x也是一个宏的话),然后再传给TO_STRING1转换为字符串,现在你可以这样:
const char *str = TO_STRING( PARAM( ADDPARAM( 1 ) ) );去一探PARAM展开后的样子。

2009年3月8日星期日

lib和dll中的导出变量可见性

dll和exe基本是一样的,所以链接上的lib文件直接并入自己的代码中,相同的部分各不相干,导出变量在各个模块中有各自的拷贝,一处修改只有自己可见。
而链接到同一个dll时,导出变量是共享的,在各个模块之间只有一份拷贝,一处修改处处可见。

2009年2月25日星期三

模板是什么

无论是类还是类模板都不能有virtual member function template.

模板类特化或者部分特化之后,就是一个独立的类.

模板参数要求的是类型,而不是变量.

2009年2月4日星期三

explicit initialization的新知

对于水母精华区里多次讲到的T t = v;的实际过程,这里(叫做explicit initialization)有很明确的解释:
其中一个之前没有注意到的问题是,尽管编译器可以将2步优化为1步,但要求copy ctor必须为public的,否则就会失败。
Even if, as in the above example, the compiler does not generate a call to the copy constructor, it must be available. This is illustrated in the following program (available as test-2.C) which does not compile. 
#include    
    class T {
        public:
        T(int i): data_(i) { std::cerr << "T::T(int)" <<>
        private:
        T(const T&) { std::cerr << "T::T(const T&)" <<>
         int data_;
     };
    int main(int, char**) {
        T t1(3); // OK
        T t2 = 3; // Error: T::T(const T&) private.
     }
For the above program, the compiler issues the following error message
test-2.C: In function `int main(int, char**)':  
test-2.C:6: `T::T(const T&)' is private  
test-2.C:13: within this context  
test-2.C:13: initializing temporary from result of `T::T(int)'

explicit

explicit 只对有一个参数(或者有多个参数,但除了第一个,其他参数都有默认值)的构造函数起作用。explicit针对的是其他类型在向某class转换时必须遵循构造函数的参数类型,而构造函数的参数类型则可以进行implicit转换。两者对应的层次不同。
google的style guide里写道:
 We require all single argument constructors to be explicit. Always put explicit in front of one-argument constructors in the class definition: explicit Foo(string name);

The exception is copy constructors, which, in the rare cases when we allow them, should probably not be explicit. Classes that are intended to be transparent wrappers around other classes are also exceptions. Such exceptions should be clearly marked with comments. 
cppreference的例子很好:

      struct foo {

      explicit foo( int a )

        : a_( a )

      { }

 

      int a_;

    };

 

    int bar( const foo & f ) {

      return f.a_;

    }

 

    bar( 1 );  // fails because an implicit conversion from int to foo

               // is forbidden by explicit.

 

    bar( foo( 1 ) );  // works -- explicit call to explicit constructor.

 

    bar( static_cast( 1 ) );  // works -- call to explicit constructor via explicit cast.

 

    bar( foo( 1.0 ) );  // works -- explicit call to explicit constructor

                        // with automatic conversion from float to int.

2009年2月2日星期一

Effective STL学习

如果STL的容器元素为指针,需要在析构时析构所有元素,而自己编写遍历析构每个元素的代码可能会由于中间出现的exception导致内存泄露。所以,推荐的做法是使用boost::shared_ptr作为容器的元素。
永不建立auto_ptr的容器,也可以说auto_ptr同STL结合并不良好。

值传递或返回时,需要确保两件事:对象应该小;必须单态。

2009年1月31日星期六

stream学习

通过stream实现文件复制
经典的方法是借助一个指定大小的Buffer,调用fopen,fread,fwrite,fclose。
通过STL的i/o stream可以简洁的实现文件复制:
ifstream ifs("infilename");
ofstream ofs("outfilename");
ofs << inf.rdbuf();
原来是有很多书还没有看过Effective STL就是其中之一。其中的Item17就是之前在DevX上看到通过swap来去除vector过剩容量的内容。而Item29就是这里的ifstreambuf_iterator>复制文本文件到字符串中。
ifstream instream("txt.txt");
string input(
istreambuf_iterator(instream.rdbuf()),
istreambuf_iterator()
);
又引出istreambuf_iterator的一个特殊之处:如果一个istreambuf_iterator对象到达stream的末尾或者由默认构造函数构造生成,则它的值为end-of-stream,类似于文件操作中的EOF。上面的string构造函数的第二个参数就是利用了这一点。
这里用到的是string的构造函数:template string (InputIterator begin, InputIterator end);