The author demonstrates or is this a real practice

I am working on the book by Michael J. Laszlo, "Computing Geometry and Computer Graphics in C ++ ." The following is a prototype template:

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

Now let's see how it defines the List constructor:

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

My question is:

What happens with the default length assignment outside {...} , and the rest inside? Are there any logical reasoning behind this?

Because, for example, before that he had announced quite a lot of things outside of {...} , and I assumed that it was his style

+4
source share
4 answers

What happens with the default length being assigned outside the brackets and the rest inside the curly braces?

This is very common and desirable. The construct is called an initialization list . For example, this

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

can be rewritten as follows:

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

Using this construct, instructs the compiler to use copy constructors for copied elements, rather than using default constructors, followed by assignment operators. In the case of assigning primitives, this is unlikely to matter, but with more complex types, initialization lists can save you several CPU cycles.

The reason the author did not put header and win assignments in the initialization list is because the forced initialization order is where it matters. The header assignment must be done before the win assignment. When you use initialization lists, the order of assignments is not controlled by the order of the items in the list: instead, it is controlled by the relative order of declaration of the corresponding class members . Based on this, he is very confused by the reader and too fragile to remain in production, so the author correctly decided to move the two destinations into the body of the constructor.

+17
source

As I read the question, you are not asking why _length initialized in the initialization list, but you are asking why header and win are not.

Suppose you had

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

What would it do? Will it initialize the header and then copy it to win , or will it be the first copy of header to win and only then set header ? You cannot tell by looking at the definition of a constructor. You can tell by looking at the constructor definition when old old assignments are used. Therefore, some (including me) may say that the code is easier to read as it is.

+6
source

This is for efficiency reasons. This region - before {} and after () is called a list of initializers. You can initialize your variable there. Instead of initializing your member variables, the compiler initializes the variables set in this list of initializers. Compare this with scenerio, where you initialize your variable inside {}. First, the compiler initializes your entire member variable, then goes into the body {}, then you reinitialize the member variables. The initializer skips this initialization step. Always start initialization in the initializer list whenever possible.

+2
source

Firstly, it is more efficient to define values ​​in the initialization list. If you do not, if you do not have a smart compiler, the values ​​will be initialized by default and assigned. For some types, this is not very efficient (although not in the class that you have there).

As to why he decided to do it this way for this one class, this is unclear. I can only assume that he could possibly catch a possible ejection from the new in a situation of lack of memory - although even there he could make new(nothrow) for what would probably be more efficient and understandable.

What he could try to do is not to drown out the order of initialization requirements for C ++ class members that are initialized in the order in which they are declared in the class definition, and not in the order in which you specified them in the initialization constructor list. This can be a real pain, although most compilers now warn you if you do this (and also allow you to change this warning to an error). In this case, it would be possible that win was declared before header , and in this case, executing win(header) in the initialization list would set win to header value, before header received initialization. Although even there I still had an initialized header in the initialization list and only put win initialization in a code block.

What really annoys me is the use of parameter lists (void). This is C-ism, and it looks ugly. Especially for default constructors and destructors.

+2
source

Source: https://habr.com/ru/post/1482599/


All Articles