C++ 重构构造函数以使用初始化列表

C++ 重构构造函数以使用初始化列表,c++,c++11,visual-studio-2012,automated-refactoring,cppcheck,C++,C++11,Visual Studio 2012,Automated Refactoring,Cppcheck,我在一个非常大的代码库(超过3M loc)上工作,我们显然有很多类,但大多数类在其构造函数中不使用初始化列表,而是在构造函数体中分配值(一些代码是很久以前编写的,因此这已成为事实上的标准)。也许这些都是由编译器优化的,但我不确定是否真的是这样 我试图推广使用初始化列表,但是有一个庞大的代码库需要更新,所以有没有工具可以自动为我做到这一点?将它指向一个类,找到所有m_var=0行并将它们移动到初始化列表(如果需要,创建它) 除了将主体内初始化转换为初始化列表外,是否有办法确定成员变量的初始化顺序正

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

我试图推广使用初始化列表,但是有一个庞大的代码库需要更新,所以有没有工具可以自动为我做到这一点?将它指向一个类,找到所有
m_var=0行并将它们移动到初始化列表(如果需要,创建它)


除了将主体内初始化转换为初始化列表外,是否有办法确定成员变量的初始化顺序正确(即,与类的头文件中定义的顺序相同?我希望CppCheck会发现这一点,但似乎没有。

您好,我是CppCheck开发人员

Cppcheck也有一个不匹配顺序的检查。但它是一个非决定性的检查

例如:

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

daniel@debian:~/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.

我们的简单检查只会在顺序不匹配时发出警告。这就是为什么它是不确定的。在上面的代码中,初始化顺序实际上并不重要-因为上面代码中的所有成员都是int,所有初始化器都是常量文本。

使用类似于OP代码基大小的比例,需要的是a。这是一个将目标语言源文件分解为编译器数据结构(通常为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 } ";

。DMS是我知道C++的唯一来源,它甚至可以处理MSV方言。 我省略了一个可能必要的“if条件”检查,以确保成员名称确实是类的成员,前提是您的构造函数没有滥用

因为您的构造函数可能没有任何初始值设定项列表,所以您需要一个助手规则来在必要时引入一个初始值设定项列表:

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)模式触发此类检查:

它需要一个检查顺序的辅助元谓词,如果它们的顺序错误,该谓词会进行投诉。您需要构造函数的名称,以使谓词能够查找相应的类并检查成员的顺序。[DMS向提供了此信息]

或者,您可以简单地使用不同的重写规则对其重新排序:

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);

这条规则本质上是对初始值设定项进行排序。[注意这是一种冒泡排序:但初始值设定项列表通常不会很长,而且每个构造函数只运行一次。]在使用前面显示的规则将所有初始值设定项从构造函数体中取出后,您将运行此规则。

至于第二部分:GCC有
-Wreorder
@Biffen做Visual Studio 2012吗?因为这是我正在使用的。据我所知,这不是我所知的,快速谷歌也没有给出任何信息。我将把它留给您来做更多的研究。
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);