Will the initialization list always be processed before the constructor code?

和自甴很熟 提交于 2020-01-02 00:47:26

问题


Will the initialization list always be processed before the constructor code?

In other words, will the following code always print <unknown>, and the constructed class will have "known" as value for source_ (if the global variable something is true)?

class Foo {
  std::string source_;
public:
  Foo() : source_("<unknown>") {
    std::cout << source_ << std::endl;
    if(something){
      source_ = "known";
    }
  }
};

回答1:


Yes, it will, as per C++11: 12.6.2 /10 (same section in C++14, 15.6.2 /13 in C++17):


In a non-delegating constructor, initialization proceeds in the following order (my bold):

  • First, and only for the constructor of the most derived class (1.8), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.

  • Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).

  • Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).

  • Finally, the compound-statement of the constructor body is executed.


The main reason for using init-lists is to help the compiler with optimisation. Init-lists for non-basic types (i.e., class objects rather than int, float, etc.) can generally be constructed in-place.

If you create the object then assign to it in the constructor, this generally results in the creation and destruction of temporary objects, which is inefficient.

Init-lists can avoid this (if the compiler is up to it, of course but most of them should be).

The following complete program will output 7 but this is for a specific compiler (CygWin g++) so it doesn't guarantee that behaviour any more than the sample in the original question.

However, as per the citation in the first paragraph above, the standard does actually guarantee it.

#include <iostream>
class Foo {
    int x;
    public:
        Foo(): x(7) {
            std::cout << x << std::endl;
        }
};
int main (void) {
    Foo foo;
    return 0;
}



回答2:


Yes, C++ constructs all the members before calling the constructur code.




回答3:


As already answered, initialization lists get completely executed before entering the constructor block. So it is completely safe to use (initialized) members in the constructor body.

You have made a comment in the accepted answer about having to refer to the constructor arguments, but not the member vars inside the constructor block. You don't.

It is possible that you mistook the fact that you should refer to parameters and not to member attributes inside the initialization list. As an example, given a class X that has two members (a_ and b_) of type int, the following constructor may be ill-defined:

 X::X( int a ) : a_( a ), b( a_*2 ) {}

The possible problem here is that the construction of the elements in the initialization list depends on the order of declaration in the class and not the order in which you type the initialization list. If the class were defined as:

class X
{
public:
   X( int a );
private:
   int b_;
   int a_; 
};

Then, regardless of how you type the initialization list in, the fact is that b_( a_*2 ) will be executed before a_ is initialized since the declaration of the members is first b_ and later a_. That will create a bug as your code believes (and probably depends) on b_ being twice the value of a_, and in fact b_ contains garbage. The simplest solution is not refering to the members:

 X::X( int a ) : a_( a ), b( a*2 ) {} // correct regardless of how X is declared

Avoiding this pitfall is the reason why you are suggested not to use member attributes as part of the initialization of other members.



来源:https://stackoverflow.com/questions/723973/will-the-initialization-list-always-be-processed-before-the-constructor-code

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!