C++11 迁移器的状态--2013年4月15日

简介: 原文地址:http://blog.llvm.org/2013/04/status-of-c11-migrator.html 译者:史宁宁(snsn1984)         自从2012年12月早些时候,C++11迁移器工具cpp11-migrate的设计文档发布以来,我们的开发工作进展顺利。

原文地址:http://blog.llvm.org/2013/04/status-of-c11-migrator.html

译者:史宁宁snsn1984

        自从2012年12月早些时候,C++11迁移器工具cpp11-migrate的设计文档发布以来,我们的开发工作进展顺利。在这篇文章里,我将介绍一下cpp11-migrate目前已经实现了哪些功能,即将实现哪些功能,以及如何加参与到这个项目里来。

         cpp11-migrate的目标是实现一个C++11迁移器,这个迁移器可以实现源码到源码的转换,使用C++11的新特性去迁移已有的C++代码,从而提高这些已有的C++代码的可维护性、可读性、运行性能以及缩短编译性能。开发工作仍然处于早期阶段,目前的转换器主要分为两类。这个迁移器是基于Clang的LibToolingAST Matching library

    目前所有的开发工作是Intel的一个小核心组在进行。我们目前工作的中心是建立起基础平台和测试,实现一小部分基本的转换器,同时确保这些转换器工作良好。我们的目标是希望可以这个工具对社区是实用的,所以我们总是聆听转换器的想法和反馈。
如何获得cpp11-migrate
      cpp11-migrate位于Clang额外工具包。构建cpp11-migrate,你将需要LLVM和Clang的源码。跟随Clang的 Getting Started instructions 指引,确保履行下载了可选的额外的工具包。一旦下载到了构建系统对应的目录,重新认证之后,将自动包含Clang额外工具包作为接下来整体构建的一部分。如果你使用的是CMake构建系统,你可以构建 cpp11-migrate通过使用cpp11-migratetarget参数。CMake提供的 check-clang-tools将运行所有Clang额外工具包括cpp11-migrate的回归测试。
目前已经实现的转换器
这个C++11迁移器目前支持C++11的四个特性:
  • 基于范围的for循环
  • 为空指针提供了nullptr关键字
  • auto类型说明符
  • override虚拟说明符
    基于范围的for循环转换器曾经作为一个单独的叫做loop-convert的工具存在过,它的贡献者是Sam Panzer。当打算开发更多的转换器的时候,实现的思路就变成了把所有的转换器放在一个单独的工具管辖之下,于是 cpp11-migrate诞生了。基于范围的for循环转换器替换了下列三种普遍情况下的任何一种for循环:
  1. 使用迭代器遍历容器:
    std::vector<int> myVec;
    for (std::vector<int>::iterator I = myVec.begin(),
                                    E = myVec.end();
         I != E; ++I)
      llvm::outs() << *I;
    
     
     
    std::vector<int> myVec;
    for (auto & elem : myVec)
      llvm::outs() << elem;
    
  2. 遍历静态数组:
    int arr[] = {1,2,3,4,5};
    for (int i = 0; i < 5; ++i)
      llvm::outs() << arr[i];
    
     
     
    int arr[] = {1,2,3,4,5};
    for (auto & elem : arr)
      llvm::outs() << elem;
  3. 使用操作符[]或者()遍历类似数组的容器:
    std::vector<int> myVec;
    for (int i = 0; i < myVec.size(); ++i)
      llvm::outs() << v[i];
    
     
     
    std::vector<int> myVec;
    for (auto & elem : myVec)
      llvm::outs() << elem;
    
     nullprt转换器使用最新的nullprt关字,当指针被被初始化或者赋值为一个空值的时候。万一这时候还有一个显式的转换存在,这个显示的转换将保留下来,避免引入两意性到代码。
void foo(int *arg);
void foo(float *arg);

int *IntPtr = 0;
float *FloatPtr = NULL;
foo(static_cast<int*>(0));
 
 
void foo(int *arg);
void foo(float *arg);

int *IntPtr = nullptr;
float *FloatPtr = nullptr;
foo(static_cast<int*>(nullptr));

        auto类型说明符转换器使用新的auto关键字替换了变量声明的类型说明符。一般来说,只要变量声明的类型和它的初始化类型相匹配,这样的替换就可以做。当然,这个转换器只是针对一小部分特殊的方便可读性和可维护性的实用场景:
  1. 当变量是一个STL容器的迭代器的时候。
    std::vector<std::pair<int, std::string> >::iterator NameAgeI = People.begin();
    for (std::vector<MyType>::iterator I = Container.begin(),
                                       E = Container.end;
         I != E; ++I) {
      // ...
    }
    
     
     
    auto NameAgeI = People.begin();
    for (auto I = Container.begin(),
                                      E = Container.end;
         I != E; ++I) {
      // ...
    }
  2. 当初始化器是一个使用new操作符的分配空间动作时。
    MyType *VarPtr = new MyType();
    MyType * const VarCPtr = new MyType();
    
     
     
    auto VarPtr = new MyType();
    auto const VarCPtr = new MyType();
    
   正在开发支持的第三种情况:使用工厂方法创建对象。
MyType *FooPtr = makeObject<MyType>(/*...*/);
MyType *BarPtr = MyType::create(/*...*/);
 
 
auto FooPtr = makeObject<MyType>(/*...*/);
auto BarPtr = MyType::create(/*...*/);
     在每一种情形之下,为声明产生的类型都应该是读者来说非常明显的。标准容器的迭代器是通过具有特殊名字的函数所创建的,并且使用在特殊的情景之下。对于工厂方法和new操作符来说,类型已经在初始化的时候表明了,所以在变量声明的时候重复说明没有必要。
       override虚拟说明符转换器,Philip Dunstan贡献,它是这个迁移器的第四个转换器并且是第一个来自Intel核心小组之外的贡献。这个转换器检测派生来之中的重载父类成员函数的虚成员函数,并且给它们加上override虚拟说明符。
class Parent {
public:
  virtual int getNumChildren();
};

class Child {
public:
  virtual int getNumChildren();
};
 
 
class Parent {
public:
  virtual int getNumChildren();
};

class Child {
public:
  virtual int getNumChildren() override;
};
      更多关于这些转换器的细节,包括它们能做什么、不能做什么,怎么样调整它们的行为,甚至了解他们的局限性,这些都可以在这个文档cpp11-migrate User's Manual中找到。

  在真实的工程上测试


    还有什么比在真实的工程上运行C++11迁移器进行测试更好的方法么?我们已经建立起了一个持续的合成服务器去构建和运行cpp11-migrate,目前已经运行了两个工程,已经有计划运行至少三个工程。对于每个工程,目标是构建转换的代码并且运行这些工程的测试包,来确保语义没有被改变。
已经实现的:
1. LLVM3.1
2. ITK 4.3.1
计划实现的:
1. LLDB
2. OpenCV
3. Poco
      在实际的代码上运行迁移器对发现缺陷很有帮助。各种项目的真实代码经常揭示转换器的实际开发和单元测试无法揭示的代码表达式。每次转换这些工程的缺陷被修复,新的测试用例都会加到回归测试包里,迁移器就会变得更加健壮。

  接下来的工作


   尽可能快的通过迁移真实的代码去修复缺陷,是目前高优先级的,因为我们想给尽可能多的用户带来很好的用户体验。添加更多的转换器是另外一个优先的任务,同时社区最感兴趣的转换器将会首先被添加。目前列表的最顶端是:
1. 使用标准库去替代TR1
2. 取代使用已经废弃的auto_prt类。
   为了修复缺陷和添加转换器,还有一些更普遍的改进需要考虑。其中之一的改进已经正在实现,那就是去除只有源文件可以转换而它所包含的任何头文件都不转换的限制。这个限制直到现在才开始做是因为迁移器需要知道哪些头文件是可以安全转换的。系统头文件和第三方库的头文件很明显是不能碰的。
    加入我们!
   如果你想加入我们,你需要做的第一件事情就是在你的代码上试试cpp11-migrate。缺陷可以使用clang-tools-extra产品下的LLVM's bug tracker 去记录。如果你需要帮助或者你希望参与的更多,可以给 Clang Developer's Mailing List发一个邮件。我们期望收到你来信!
Labels: C++, Clang
Location: Waterloo, ON, Canada

目录
相关文章
|
Web App开发 Rust 分布式计算
Rust与C++的区别及使用问题之对于大量使用C++实现的产品来说,迁移到Rust的问题如何解决
Rust与C++的区别及使用问题之对于大量使用C++实现的产品来说,迁移到Rust的问题如何解决
309 1
|
存储 算法 编译器
C++ 从cstring函数向string类成员函数迁移2
C++ 从cstring函数向string类成员函数迁移
432 0
|
算法 编译器 C++
C++ 从cstring函数向string类成员函数迁移
C++ 从cstring函数向string类成员函数迁移
457 0
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
编译器 C++ 容器
【c++11】c++11新特性(上)(列表初始化、右值引用和移动语义、类的新默认成员函数、lambda表达式)
C++11为C++带来了革命性变化,引入了列表初始化、右值引用、移动语义、类的新默认成员函数和lambda表达式等特性。列表初始化统一了对象初始化方式,initializer_list简化了容器多元素初始化;右值引用和移动语义优化了资源管理,减少拷贝开销;类新增移动构造和移动赋值函数提升性能;lambda表达式提供匿名函数对象,增强代码简洁性和灵活性。这些特性共同推动了现代C++编程的发展,提升了开发效率与程序性能。
497 12
|
11月前
|
人工智能 机器人 编译器
c++模板初阶----函数模板与类模板
class 类模板名private://类内成员声明class Apublic:A(T val):a(val){}private:T a;return 0;运行结果:注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。return 0;
265 0
|
11月前
|
存储 编译器 程序员
c++的类(附含explicit关键字,友元,内部类)
本文介绍了C++中类的核心概念与用法,涵盖封装、继承、多态三大特性。重点讲解了类的定义(`class`与`struct`)、访问限定符(`private`、`public`、`protected`)、类的作用域及成员函数的声明与定义分离。同时深入探讨了类的大小计算、`this`指针、默认成员函数(构造函数、析构函数、拷贝构造、赋值重载)以及运算符重载等内容。 文章还详细分析了`explicit`关键字的作用、静态成员(变量与函数)、友元(友元函数与友元类)的概念及其使用场景,并简要介绍了内部类的特性。
421 0
|
编译器 C语言 C++
类和对象的简述(c++篇)
类和对象的简述(c++篇)
|
设计模式 安全 C++
【C++进阶】特殊类设计 && 单例模式
通过对特殊类设计和单例模式的深入探讨,我们可以更好地设计和实现复杂的C++程序。特殊类设计提高了代码的安全性和可维护性,而单例模式则确保类的唯一实例性和全局访问性。理解并掌握这些高级设计技巧,对于提升C++编程水平至关重要。
253 16
|
编译器 C++
类和对象(中 )C++
本文详细讲解了C++中的默认成员函数,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载和取地址运算符重载等内容。重点分析了各函数的特点、使用场景及相互关系,如构造函数的主要任务是初始化对象,而非创建空间;析构函数用于清理资源;拷贝构造与赋值运算符的区别在于前者用于创建新对象,后者用于已存在的对象赋值。同时,文章还探讨了运算符重载的规则及其应用场景,并通过实例加深理解。最后强调,若类中存在资源管理,需显式定义拷贝构造和赋值运算符以避免浅拷贝问题。