作者是在炫耀还是真正的实践?

is the author showing off or is it a real practice

本文关键字:      更新时间:2023-10-16

我正在研究Michael J Laszlo的书《c++中的计算几何和计算机图形学》。下面是一个模板类原型:

template <class T> class ListNode : public Node {    
    T _val;
    ListNode (T val);
    friend class List<T>;
};
template <class T> ListNode <T>::ListNode(T val)
{_val=val;};
template <class T> class List{    
  private:
    ListNode <T> *header;
    ListNode <T> *win;
    int _length;
  public:
    List(void);
    ~List(void);
    T insert(T);
    T append(T);
    List * append(List*);
    T prepend(T);
    T remove(void);
    void val(T); // overloaded function!
    T val(void);// overloaded function!
    T next(void);
    T prev(void);
    T first(void);
    T last(void);
    int length(void);
    bool isFirst(void);
    bool isLast(void);
    bool isHead(void);
};    

现在看一下他定义List构造函数的方式:

//  constructors and destructors
template <class T> list<T>:: List(void): _length(0)
{    
    header =new ListNode<T>(NULL);
    win=header;
}

我的问题:

{...}外部和其余内部分配默认长度是怎么回事?这背后有什么逻辑推理吗?

因为在此之前,他几乎声明了{...}之外的所有内容我认为这就是他的风格

在括号外赋值默认长度,其余部分在花括号内赋值是怎么回事?

这是非常普遍和可取的。该构造称为初始化列表。例如,

template <class T> ListNode <T>::ListNode(T val)
{_val=val;};

可以重写为:

template <class T> ListNode <T>::ListNode(T val)
: _val(val) {};

使用此构造指示编译器对要复制的项使用复制构造函数,而不是使用默认构造函数后跟赋值操作符。在分配原语的情况下,这几乎无关紧要,但是对于更复杂的类型,初始化列表可以节省一些CPU周期。

作者没有将headerwin赋值放入初始化列表的原因是为了在重要的地方强制执行特定的初始化顺序。对header的赋值必须发生在对win赋值之前。当使用初始化列表时,赋值顺序不受列表中项的顺序控制:相反,它由类中相应成员声明的相对顺序控制。依赖它会让读者感到非常困惑,而且在生产环境中也太脆弱,因此作者正确地决定将这两个赋值移到构造函数的主体中。

我阅读问题的方式,你不是在问为什么_length在初始化器列表中初始化,但你问为什么headerwin不是。

假设有

template <class T> List<T>::List(void)
    : _length(0)
    , header(new ListNode<T>(NULL))
    , win(header)
{ }

这有什么用?这将初始化header,然后将其复制到win,还是首先将header复制到win,然后才设置header ?您无法通过查看构造函数定义来判断。您可以通过查看构造函数定义来判断何时使用了普通的旧赋值。所以有些人(包括我自己)可能会说这样的代码更容易阅读。

这是出于效率的考虑。在{}之前和()之后的区域称为初始化列表。你可以在这里初始化变量。编译器不会默认初始化成员变量,而是初始化该初始化列表中设置的变量。将其与在{}中初始化变量的场景进行比较。编译器首先初始化所有成员变量,然后进入主体{},然后重新初始化成员变量。初始化程序跳过初始化步骤。如果可能,总是在初始化列表中初始化。

首先,在初始化器列表中定义值更有效。如果你不这样做,除非你有一个聪明的编译器,这些值将被默认初始化,并被赋值。对于某些类型,这不是非常有效(尽管不是在您的类中)。

至于他为什么决定在这一节课上这样做,还不清楚。我只能假设这样做是为了在内存不足的情况下,他可以抓住new可能抛出的错误——尽管即使在那里,他也可以为此执行new(nothrow),这可能既有效又清晰。

他可能试图做的是不违反c++初始化要求的顺序——类成员是按照它们在类定义中声明的顺序初始化的,而不是按照你在构造函数初始化列表中指定的顺序。这可能是一个真正的痛苦,尽管现在大多数编译器都会警告您这样做(并且还允许您将该警告更改为错误)。在这种情况下,win可能在header之前被声明,在这种情况下,在初始化器列表中执行win(header)将在header被初始化之前将win设置为具有header的值。尽管如此,我仍然会在初始化器列表中初始化header,并且只将win的初始化放在代码块中。

真正让我恼火的是他使用(void)参数列表。这是C-ism,看起来很丑。特别是默认构造函数和析构函数

相关文章:
  • 没有找到相关文章