C++的可移植性和跨平台开发[2]--语法

目前还有相当一部分开发人员在使用老式编译器干活,这些老式编译器可能对C++98支持不够。因此,当你的代码移植到这些老式的编译器上时,可能会碰到一些稀奇古怪的问题(包括编译出错和运行时错误)。下面这些注意事项有助于你绕过这些问题。
  强调一下,后面提到的好几个条款都是通过回避C++的新语法来保证移植性。如果你用的是新式编译器,那么你可以不理会这些条款。

  ★小心for循环变量的作用域(不支持新标准)

  在C++98标准中,for循环变量的作用域局限在循环体内。而某些老的编译器(例如Visual C++ 6)认为for循环变量的作用域在循环体外。所以如下的代码可能导致移植问题。

Cpp代码 复制代码  收藏代码
  1. {   
  2.  for(int i=0; i<XX; i++)   
  3.  {   
  4.   // ...   
  5.  }   
  6.  for(int i=0; i<XXX; i++)   
  7.  {   
  8.   // ...   
  9.  }   
  10. }  
{
 for(int i=0; i<XX; i++)
 {
  // ...
 }
 for(int i=0; i<XXX; i++)
 {
  // ...
 }
}

 

  建议修改为不同的循环变量,如下所示:

Cpp代码 复制代码  收藏代码
  1. {   
  2.  for(int i=0; i<XX; i++)   
  3.  {   
  4.   // ...   
  5.  }   
  6.  for(int j=0; j<XXX; j++)   
  7.  {   
  8.   // ...   
  9.  }   
  10. }  
{
 for(int i=0; i<XX; i++)
 {
  // ...
 }
 for(int j=0; j<XXX; j++)
 {
  // ...
 }
}

 

  ★不要使用全局类对象,改用单键(标准未定义)

  全局类对象的构造函数先于main()函数执行,如果某个模块中同时包含若干个全局类对象,则它们的构造函数的调用顺序是不确定的。而单键是在第一次调用时被初始化,能避免此问题。另外,单键虽然解决了构造问题,但是析构依然有隐患。详见“C++ 对象是怎么死的?进程篇”。

  ★保持inline函数尽量简单

  不要在inline函数内部使用局部静态变量,不要在inline函数使用可变参数。这些都有可能导致移植问题。

  ★不要依赖函数参数的求值顺序(标准未定义)


  标准没有明确规定函数参数的求值顺序。因此,如下的代码行为是不确定的。

Cpp代码 复制代码  收藏代码
  1. void Foo(int a, int b);   
  2. int n = 1;   
  3. foo(++n, ++n);  
void Foo(int a, int b);
int n = 1;
foo(++n, ++n);

 

  ★慎用模板特化(不支持新标准)

  有些老式编译器对偏特化或全特化支持不够。

  ★模板继承中,引用基类成员要小心(不支持新标准)

  看如下例子:

Cpp代码 复制代码  收藏代码
  1. template <typename T>   
  2. class TBase   
  3. {   
  4. protected:   
  5.  typedef std::vector<T> Container;   
  6.  Container m_container;   
  7. };   
  8. template <typename T>   
  9. class TDerived : public TBase<T>   
  10. {   
  11.  typedef TBase<T> BaseClass;   
  12. public:   
  13.  void Func()   
  14.  {   
  15.   typename BaseClass::Container foo;  //可移植   
  16.   Container foo; //不可移植   
  17.   this->m_container.clear(); //可移植   
  18.   m_container.clear(); //不可移植   
  19.  }   
  20. };  
template <typename T>
class TBase
{
protected:
 typedef std::vector<T> Container;
 Container m_container;
};
template <typename T>
class TDerived : public TBase<T>
{
 typedef TBase<T> BaseClass;
public:
 void Func()
 {
  typename BaseClass::Container foo;  //可移植
  Container foo; //不可移植
  this->m_container.clear(); //可移植
  m_container.clear(); //不可移植
 }
};

 

  ★慎用RTTI(不支持新标准、标准未定义)

  先声明一下,我这里说的RTTI主要是指typeid操作符和type_info类型。

  首先,由于某些老式编译器可能不支持typeid操作符和type_info类型,会导致移植性的问题,这是慎用RTTI的一个原因。(如果你用的是新式编译器,不用考虑这个因素)

  其次,由于标准对于type_info类型的约束比较简单。这导致了不同的编译器对type_info的实现有较大差异。如果你确实要使用type_info类型,建议仅仅使用它的operator==和operator!=这两个成员函数。

  所以,如果你确实需要在运行时确定类型,又不想碰到上述问题,可以考虑在自己的类体系中加入类型信息来实现。比如MFC和wxWidgets都是这么干的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值