【问题标题】:Constructor initialization Vs assignment构造函数初始化 Vs 赋值
【发布时间】:2013-03-28 10:56:21
【问题描述】:

让我们考虑以下类

class test1
{
    private:
        int a;
        int b;
    public:
        test1():a(0),b(0){}
};

class test2
{
    private:
        int a;
        int b;
    public:
        test2()
        {
            a=0;
            b=0;
        }
};

现在,我知道test1() 构造函数是初始化class 的数据成员的正确方法,因为在test2() 中我们执行的是赋值而不是初始化。我的问题是:

  1. 如果我们执行赋值而不是初始化,可能会出现什么问题?
  2. 在test1()构造函数的情况下,编译器不内部执行赋值吗?如果不是,那么这些是如何初始化的?

【问题讨论】:

标签: c++ constructor


【解决方案1】:

如果我们执行赋值而不是初始化会出现什么问题?

无法分配某些类类型(以及引用和const 对象);有些不能默认初始化;有些默认初始化和重新分配可能比直接初始化更昂贵。

在 test1() 构造函数的情况下,编译器不是在内部执行赋值吗?如果没有,那么这些是如何初始化的?

对于像int 这样的原始类型,两者之间几乎没有实际区别。默认初始化什么都不做,直接初始化和赋值都做同样的事情。

在类类型的情况下,default-initialisation、assignment和direct-initialisation各自调用不同的用户自定义函数,有些操作可能根本不存在;所以总的来说,这两个例子的行为可能非常不同。

【讨论】:

    【解决方案2】:

    对于您的示例,没有真正的不同,因为您正在初始化纯整数。

    但假设这些整数是带有构造函数的对象,那么编译器会生成以下调用:

    // test1
    a::copy_constructor(0);
    b::copy_constructor(0);
    
    
    // test2
    a::default_constructor();
    b::default_constructor();
    a::operator = (0);
    b::operator = (0);
    

    因此,根据您的对象 test2 可能会对性能产生巨大影响。此外,通过在初始化列表中初始化您的对象,可以保证您的变量在您进入构造函数时具有数据。初始化列表的一个“缺点”是它是按照声明变量的顺序执行的,而不是按照初始化列表的顺序执行的,因此您可能不想使用初始化列表。

    【讨论】:

      【解决方案3】:

      使用direct-list-initialization 的第三个变体。优点是

      1. 变量不必在构造函数中默认初始化
      2. 构造函数而不是复制/移动赋值运算符用于构造成员(正如其他答案所说,本示例的原始类型无关紧要)

      所以这比问题中的两个变体更不容易出错:

      #include <iostream>
      class Test3
      {
          public: // Made public so we can easily output the vars. No struct is used to be consistent with question.
              int a { 4 }; // No need for separate initialization in constructor.
              int b { 2 }; // No need for separate initialization in constructor.
      };
      int main()
      {
          const auto t = std::move(Test3()); // Implicitly-declared default constructor + implicitly-declared move assignment operator
          std::cout << t.a << t.b;
      }
      

      输出是42。

      【讨论】:

      • int a { 4 } 和 int a = 4 有区别吗?后者似乎也有效。
      • 对于像 int 这样的原始类型没有区别。但是有些对象不能被复制初始化,因此我提出了直接(列表)初始化而不是复制(列表)初始化。第一个作品例如也适用于不可复制的对象以及显式和非显式构造函数。
      【解决方案4】:

      构造函数初始化器允许在数据成员的时候初始化它们 创作。

      一些程序员更喜欢在构造函数的主体中分配初始值。但是,必须在构造函数初始化程序中初始化几种数据类型。以下几行总结了它们:

      • 常量数据成员

      您不能合法地为 const 变量赋值 创建后。任何值都必须在 创建时间。

      • 引用数据成员

      没有引用就不能存在引用 东西。

      • 没有默认构造函数的对象数据成员

      C++ 尝试使用 默认构造函数。如果不存在默认构造函数,则 无法初始化对象。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多