【问题标题】:Must a reference type be initialized in constructor initialization list?必须在构造函数初始化列表中初始化引用类型吗?
【发布时间】:2013-08-01 10:56:28
【问题描述】:

作为自我练习,我写了这个简单的代码:

#include <iostream>

int gIndex = 3;

template <class T> class Array
{
public:
    explicit Array(int size);
    T& operator[](int i) { return m_data[i]; }
    T operator[](int i) const { return m_data[i]; }
    T getAnchorPoint() const { return m_data[m_anchor]; }
private:
    T* m_data;
    int m_size;
    int& m_anchor;
};

template <class T> Array<T>::Array(int size) : m_size(size), m_data(new T[size])
{
    memset(m_data, 0, size*sizeof(T));
    m_anchor = gIndex;
}

int main()
{
    Array<double> a(10);
    return 0;
}

我得到一个编译错误,上面写着:

error C2758: 'Array&lt;T&gt;::m_anchor' : must be initialized in constructor base/member initializer list

从来没有发生过,是什么让我问这个问题:

必须在构造函数初始化列表中初始化任何类成员引用类型吗?

如果是这样,为什么?这是否与无法重新分配引用类型这一事实有关?

在构造函数初始化列表中是否还有更多类型必须初始化?

【问题讨论】:

    标签: c++ reference


    【解决方案1】:

    任何类成员引用类型都必须在构造函数初始化列表中初始化吗?

    是的。

    如果是这样,为什么?这是否与永远无法重新分配引用类型的事实有关?

    这是部分原因。另一部分是因为引用必须被初始化,并且它没有默认构造函数。

    构造函数初始化列表中是否还有更多类型必须初始化?

    任何没有赋值运算符(无论是复制还是移动)或默认构造函数的类型。这显然包括(但不限于)const 成员,因为它们一旦构建就无法修改。


    根据经验,你应该(几乎)总是更喜欢在构造函数的初始化列表中初始化你的成员:为什么浪费循环首先默认构造一个对象,然后只分配给它(如果这甚至可能的话),当你能正确地构造它吗?

    【讨论】:

    • 我真的不好意思问这个,但是引用类型没有赋值运算符?
    • @user1798362 不,引用它只是其他东西的别名。当您“分配”给一个引用时,您实际上是分配给它所引用的对象。
    【解决方案2】:

    必须在构造函数初始化列表中初始化任何类成员引用类型吗?

    是的。

    这是否与无法重新分配引用类型这一事实有关?

    是的,再加上没有“null”或默认构造的引用这一事实。它是另一个对象的别名,并且必须从一开始就绑定到它。你不能这样做(这不在类定义中):

    int main()
    {
      int& iref; // ERROR
      int i = 42;
      int& iref2 = i; // OK
    }
    

    因为iref 必须为 something 别名。

    【讨论】:

    • 感谢这个例子,现在我完全明白了!
    【解决方案3】:
    Must any class-member reference type be initialized in the constructor initialization list?
    

    是的,我们应该始终使用初始化列表来初始化类的引用成员。

    If so, why? Is that related somehow to the fact that a reference type can never be reassigned?
    

    构造函数有两个阶段,即初始化和计算。因此,即使您不为数据成员使用初始化列表,编译器也会使用随机值对其进行初始化。在通常以构造函数主体的“{”开头的计算阶段中,如果您进行赋值,那么编译器会抱怨,因为引用成员已经初始化。因此,初始化此类成员的唯一机会是构造函数初始化程序列表。

    Are there more types that must be initialized in constructor initialization list?
    

    是的,const 数据成员是您需要初始化列表的另一种类型。

    【讨论】:

    • 编译器不会因为赋值而抱怨(赋值给引用实际上是赋值给被引用的对象,这没有问题)或者因为引用已经初始化,而是因为它 一开始没有初始化(这是非法的)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-24
    • 1970-01-01
    • 2013-11-03
    • 2012-03-19
    相关资源
    最近更新 更多