2016-11-14 125 views
2

我正在一个非常大的代码库(超过3M loc),我们显然有很多类,但他们大多数不在他们的构造函数中使用初始化列表,而是分配值构造函数体(一些代码在很久以前被写入了一个LONG,所以这已经成为事实上的标准)。也许这些被编译器优化掉了,但我不确定是否真的如此。重构构造函数使用初始化列表

我想推广初始化列表的使用,但有一个大的代码库需要提供最新的,所以有没有任何工具会自动为我做这个?将它指向一个类,找到所有m_var = 0;行并将它们移动到初始化列表(如果需要,创建它)。

除了将体内初始化转换为初始化列表外,是否有一种方法可以找到成员变量是按照正确的顺序初始化的(即它们在类头文件中定义的顺序相同?本来希望CppCheck会挑这个,但它似乎没有没有。

+1

至于第二部分:GCC有'-Wreorder'。 – Biffen

+0

@Biffen是不是Visual Studio 2012?这就是我正在使用的。 – fwgx

+1

不是我所知道的,一个快速的谷歌没有给任何东西。我会留给你做更多的研究。 – Biffen

回答

2

你好,我是一个cppcheck开发商。

Cppcheck也有不匹配顺序检查,但它是一个不确定的检查。

例如:

class Fred { 
public: 
    Fred() : y(0), x(0) {} 
    int x; 
    int y; 
}; 

Cppcheck输出:

[email protected]:~/cppcheck$ ./cppcheck --enable=style --inconclusive 1.cpp 
Checking 1.cpp ... 
[1.cpp:3] -> [1.cpp:4]: (style, inconclusive) Member variable 'Fred::x' is in the wrong place in the initializer list. 

我们简单的检查将只警告时的顺序不匹配。这就是为什么它没有结果。在上面的代码中,初始化顺序实际上并不重要 - 因为上面代码中的所有成员都是整数,所有初始化方法都是常量文字。

1

与OP的代码库大小一样,需要的是program transformation system (PTS)。这是一个将目标语言源文件解析为编译器数据结构(通常是AST)的工具,允许您将转换应用到AST,然后可以重新生成有效的源代码,包括修改程序的原始注释。把PST看作在大型中重构的工具。

一个很好的PTS将让你写源到源转换形式的

when you see *this*, replace it by *that* if *condition* 

其中在目标语言的语法表达,其中仅当源代码与显式语法匹配时才匹配。 [这些不是字符串匹配;他们在AST上工作,所以布局不会影响他们匹配的能力]。

你需要钥匙规则看起来是这样的:

rule move_to_initializer(constructor_name:IDENTIFIER, 
         arguments: argument_list, 
         initializer_list: initializer, 
         member_name:IDENTIFIER, 
         initializer_expression: expression, 
         statements: statement_list 
         ): constructor -> constructor = 
    " \constructor_name(\arguments): \initializer_list 
      { \member_name = \initializer_expression ; 
      \statements } " 
    -> " \constructor_name(\arguments): \initializer_list, \member_name(\initializer_expression) 
      { \statements } "; 

The syntax of these rules/patterns for our DMS Software Reengineering Toolkit is explained here。 DMS是唯一可以处理C++的源码到源码PTS;它甚至可以处理MSVS方言]。

我忽略了可能必要的“如果条件”检查成员名称确实是类的成员,假设您的构造函数不是滥用。

因为你的构造可能没有任何初始化列表,你需要一个帮手规则介绍一个在必要时:

rule move_to_initializer(constructor_name:IDENTIFIER, 
         arguments: argument_list, 
         member_name:IDENTIFIER, 
         initializer_expression: expression, 
         statements: statement_list 
         ): constructor -> constructor = 
    " \constructor_name(\arguments) 
      { \member_name = \initializer_expression ; 
      \statements } " 
    -> " \constructor_name(\arguments): \member_name(\initializer_expression) 
      { \statements } "; 

      { \member_name = \e ; } " 

不变的是你需要额外的规则,以涵盖其他特殊情况,但它不应该超过一些。

关于对订单的初始化检查,则可以使用(DMS)图案触发这样的检查:

pattern check_initializer_order(constructor_name:IDENTIFIER, 
         initializer_list: initializer, 
         statements: statement_list 
         ): constructor = 
    " \constructor_name(): \initializer_list, 
      { \statements } " 
      if complain_if_not_ordered(constructor_name,initializer_list); 

这需要一个辅助的元谓词检查顺序,如果它们是抱怨乱序。您需要constructor_name来使谓词能够查找相应的类并检查成员的顺序。 [DMS向means to access a symbol table提供这些信息]。

或者,你可能只是简单地重新排列它们使用不同的重写规则:

rule order_initializers(constructor_name:IDENTIFIER, 
         arguments: argument_list, 
         initializer_list_prefix: initializer, 
         initializer_list_suffix: initializer, 
         member1_name:IDENTIFIER, 
         initializer1_expression: expression, 
         member2_name:IDENTIFIER, 
         initializer2_expression:expression,        
         statements: statement_list 
         ): constructor -> constructor = 
    " \constructor_name(\arguments): 
      \initializer_list_prefix, 
      \member1_name(\initializer1), 
      \member2_name(\initializer2), 
      \initialize_list_suffix 
      { \statements } " 
    -> 
    " \constructor_name(\arguments): 
      \initializer_list_prefix, 
      \member2_name(\initializer2), 
      \member1_name(\initializer1), 
      \initialize_list_suffix 
      { \statements } " 
     if is_wrong_order(constructor_name,member1_name,member2_name); 

这个规则基本上排序初始化。 [请注意,这是一个冒泡排序:但是初始化列表通常不会很长,并且您只需要为每个构造函数运行一次。]在将所有初始化器从构造函数体中提取出来之后,您将运行此规则前面显示的规则。