【问题标题】:Fix warning: 'Foo::fooObj1' should be initialized in the member initialization list [-Weffc++]修复警告:'Foo::fooObj1' 应该在成员初始化列表中初始化 [-Weffc++]
【发布时间】:2021-10-19 07:52:08
【问题描述】:

foo.h

#ifndef FOO_H
#define FOO_H

class Foo
{
    int fooObj1;
    bool fooObj2;
public:
    Foo(int input1);
};

#endif

foo.cpp

#include "foo.h"

Foo::Foo(int input1)
{
    fooObj1 = input1;
    // some code logic to decide the value of fooObj2 (an example)
    // so I can't really do member initialization list.
    fooObj2 = (fooObj1 % 2 == 0);
}

所以我关注了tutorial,他们告诉我打开[-Weffc++] 并将警告视为错误。但是当我这样做时,[-Weffc++] 会发出警告: 'Foo::fooObj1' should be initialized in the member initialization list [-Weffc++] 和 'Foo::fooObj2' should be initialized in the member initialization list [-Weffc++]。但是我不能在这个项目中真正做成员初始化列表。那么我该如何重新接受这个警告呢?

【问题讨论】:

  • 在线教程不值得您为它们支付。获取good book。
  • ` 但是我不能在这个项目中做成员初始化列表。` ehm,为什么?它是自 1987 年以来语言的核心特征(它的构想)
  • @Swift-FridayPie 因为嵌套if-else 会使逻辑复杂化,所以不太适合
  • @justANewbie 有效性警告实际上会提示您尽可能避免这种情况。我仍然没有看到问题。无论您需要什么条件初始化,都可以解决,或者您的设计本身就考虑不周。您展示的示例是完全可内联的,如果使用 list 可以静态初始化,您的版本会创建额外的函数调用和代码。
  • @justANewbie 将逻辑包装在一个返回所需值的函数中; Foo::Foo(int i) : fooObj1(i), fooObj2(complicated_logic(fooObj1)) {}.

标签: c++ c++11 weffc++


【解决方案1】:
Foo::Foo(int input1)
   : fooObj1(input1)
   , fooObj2(input1 % 2 == 0)
{
}

请注意,fooObj2 的值是根据 input1 参数计算的,而不是 fooObj1 的值。原因是,如果您要更改标题中的顺序:

class Foo
{
    bool fooObj2;
    int fooObj1;
public:
    Foo(int input1);
};

如果你从 fooObj1 计算 fooObj2,你最终会进入 fooObj1 的未初始化内存。成员按照它们在类中出现的顺序进行初始化,而不是按照它们在构造函数的初始化列表中出现的顺序。

【讨论】:

    【解决方案2】:

    消除警告的两种解决方案。

    解决方案 1

    制作一些静态方法,比如CalculateFooObj2InitialValue,并在成员初始化列表中使用它。

    Foo::Foo(int input1):
      fooObj1(input1),
      fooObj2(CalculateFooObj2InitialValue(input1)) {
      ...  
    }
    

    解决方案 2

    使用成员初始化列表中的默认值初始化fooObj2,但意义不大。然后再计算一个有意义的初始值并赋值。

    Foo::Foo(int input1):
      fooObj1(input1),
      fooObj2{} {
      // some code logic to decide the value of fooObj2 (an example)
      // so I can't really do member initialization list.
      fooObj2 = (fooObj1 % 2 == 0);
    }
    

    【讨论】:

      【解决方案3】:
          
      Foo::Foo(int input1) : fooObj1(input1), fooObj2(0 == input1 % 2) {}
      

      【讨论】:

        【解决方案4】:

        -Weffc++ 会产生一些偏执的警告,但您想要遵循一个理想。例如。你总是可以做部分列表:

        Foo::Foo(int input1) : fooObj1(input1) /*, fooObj2() still can be here */
        {
            // some code logic to decide the value of fooObj2 (an example)
            // so I can't really do member initialization list.
            fooObj2 = (fooObj1 % 2 == 0);
        }
        

        注意,构造函数主体中的代码不是初始化。这是一个任务。 类的成员仍按其声明的顺序进行初始化,并使用实现定义或不确定的值。

        在某些多线程的情况下,如果 Foo 的成员是原子的并且某些东西可能同时访问它们,则差异可能很重要。

        分析逻辑很重要,它是否需要分支,它实际上是编译时已知的常量吗?可以用简单的三元进行初始化吗?

        在复杂的情况下fooObj2 甚至可能是另一个类类型的对象,其自身的 ctor 隐藏了“复杂逻辑”,以避免确定初始化顺序时出现问题。

        【讨论】:

          猜你喜欢
          • 2012-12-09
          • 2011-07-14
          • 2015-09-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-09-10
          • 2015-04-27
          • 2015-02-07
          相关资源
          最近更新 更多