Go A big misunderstanding of C + +--in-depth explanation of the difference between direct initialization and replication initialization

Source: Internet
Author: User


From: http://blog.csdn.net/ljianhui/article/details/9245661 Not long ago, I published an article on the blog-10 simple ways to improve the efficiency of the program, for the last point, more use of direct initialization, A lot of readers have asked me questions and written some test procedures to show that direct initialization is the same thing as replication initialization. Let me understand that the difference between direct initialization and replication initialization is really not clear, admittedly, the example of the article is not very good, here apologize! So I think it's still necessary to share with you a bit more about my understanding of direct initialization and copy initialization. First, in the primer, let's take a look at what the classics say: "When used with class-type objects, the initialization has a different copy form and direct form: direct initialization directly invokes the constructor that matches the argument, and replication initialization always calls the copy constructor. Copy initialization first creates a temporary object with the specified constructor, and then copies that temporary object to the object being created with the copy constructor. "There's another way to say," There is usually a difference between direct initialization and replication initialization only for low-level optimizations, however, for types that do not support replication, or when using non-explicit constructors, they are essentially different: Ifstream file1 ("filename")://ok:direct initializationifstream file2 = "filename";// Error:copy constructor is private "second, the usual misunderstanding from the above, we can know that the direct initialization is not necessarily called the copy constructor, and replication initialization must call the copy constructor. However, most people think that the direct initialization is to call the copy constructor when constructing the object, while the copy initialization is to call the assignment operation function (operator=) when constructing the object, which is a big misunderstanding. Because only the object is created and the initialization occurs, the assignment action is not applied to the object creation process, and primer does not. As to why this misunderstanding occurs, it may be because of an equal sign (=) in the copy initialization notation. In order to clarify the problem, or to explain it from the code is easier to understand, see the following code:[CPP]View Plaincopyprint?

#include <iostream>
#include <cstring>
Using namespace std;
Class Classtest
{
Public
Classtest ()
{
C[0] = ' + ';
cout<<"Classtest ()" <<endl;
}
classtest& operator= (const classtest &ct)
{
strcpy (c, ct.c);
cout<<"classtest& operator= (const classtest &ct)" <<endl;
return * this;
}
Classtest (const char *pc)
{
strcpy (c, PC);
cout<<"classtest (const char *pc)" <<endl;
}
Private
Classtest (const classtest& CT)
{
strcpy (c, ct.c);
cout<<"classtest (const classtest& CT)" <<endl;
}
Private
Char c[256];
};
int main ()
{
cout<<"Ct1:";
Classtest ct1 ("AB"); Direct Initialization
cout<<"CT2:";
Classtest ct2 = "AB"; Replication Initialization
cout<<"CT3:";
Classtest ct3 = Ct1; //Replication initialization
cout<<"Ct4:";
Classtest Ct4 (CT1); //Direct initialization
cout<<"CT5:";
Classtest ct5 = Classtest (); //Replication initialization
return 0;
}


The output is as follows: From the result of the output, we can know which functions are called by the object's construction, and it can be seen from the comparison between Ct1 and Ct2, CT3 and Ct4 that the Ct1 and Ct2 objects are constructed with the same function--classtest (const char *pc). Similarly, CT3 and ct4 invoke the same function--classtest (const classtest& CT), while CT5 calls the default constructor directly. Therefore, many people think Classtest ct1 ("AB"), equivalent to classtest ct2 = "AB", while classtest ct3 = Ct1, also equivalent to Classtest Ct4 (CT1), and they do not call the assignment operation function, So they are all directly initialized, but is the fact really as you think? The answer is obviously not. Third, the level of advancement, in the end who deceive us many times, their eyes tend to deceive yourself, here is an example, it is your eyes deceived you. Why is that? The reasons for this in the optimization of the supplement is also explained that because the compilation will help you do a lot of you do not see, you do not know the optimization, you see the results, it is the compiler to do the optimized code running results, not your code really running results. You may not believe what I'm saying, so you can uncomment the line in the Copy function function in the class and let the copy constructor become a private function and then compile and run the program to see what happens. Obviously, a compilation error has occurred from the above running results, you might think that because Ct3 and Ct4 used the copy constructor--classtest (const classtest& CT) During the build process, and now it becomes a private function that cannot be used outside of the class, So there is a compile error, but you can also annotate the function statements of CT3 and Ct4 as follows:[CPP]View Plaincopyprint?

int main ()
{
cout<<"Ct1:";
Classtest ct1 ("AB");
cout<<"CT2:";
Classtest ct2 = "AB";
cout<< "CT3:";
Classtest ct3 = Ct1;
cout<< "Ct4:";
Classtest Ct4 (CT1);
cout<<"CT5:";
Classtest ct5 = Classtest ();
return 0;
}


However, you are still very sorry to find that it is still not compiled through. What is this for? From the above statement and the results of the previous run, it is true that the copy constructor has not been called, why or compile errors? After an experiment, the main function only has this ability to compile:[CPP]View Plaincopyprint?

int main ()
{
cout<<"Ct1:";
Classtest ct1 ("AB");
return 0;
}


Here we can see that it turned out that the copy constructor deceived us.

   Uncovering the truth

Seeing this, you may have been frightened, let me reveal the truth below! Or that sentence, what is direct initialization, and what is replication initialization? To put it simply, the definition of the object is different. One uses parentheses, such as ClassTest ct1 ("ab"), and one uses an equal sign, such as ClassTest ct2 = "ab". But in essence, they are essentially different: direct initialization directly calls the constructor that matches the actual parameters, and copy initialization always calls the copy constructor. Copy initialization first uses the specified constructor to create a temporary object, and then uses the copy constructor to copy that temporary object to the object being created. So when the copy constructor is declared private, all copy initializations cannot be used. Now let's look at the statement in the main function again.

 1. ClassTest ct1 ("ab"); This statement is a direct initialization. It does not need to call the copy constructor. It directly calls the constructor ClassTest (const char * pc), so when the copy constructor becomes private it can Performed directly.

   2. ClassTest ct2 = "ab"; This statement is initialized for replication. It first calls the constructor ClassTest (const char * pc) to create a temporary object, and then calls the copy constructor, taking this temporary object as a parameter, and constructing the object ct2. ; So when the copy constructor becomes private, the statement does not compile.

  3. ClassTest ct3 = ct1; This statement is initialized for copying, because ct1 already exists, so there is no need to call the relevant constructor, but directly call the copy constructor and copy its value to the object ct3; so when the copy constructor changes When private, the statement will not compile.

  4, ClassTest ct4 (ct1); This statement is directly initialized, because ct1 already exists, directly call the copy constructor to generate a copy object ct4 of the object ct3. So when the copy constructor becomes private, the statement won't compile. Note: The function called for the creation of the fourth object ct4 and the third object ct3 is the same, but I think that the reason for calling the copy function is different. Because direct initialization calls the constructor according to parameters, such as ClassTest ct4 (ct1), it is directly determined to call the copy constructor ClassTest (const ClassTest & ct) based on the parameters in brackets (an object of this class). When overloading with a function, it makes sense to call the corresponding function according to the parameters when the function is called; it is different for ct3, which is not the same as when ct4, it is determined by the parameters to call the copy constructor It's just that the copy constructor must be called for initialization. It is supposed to create a temporary object, but this object already exists, so this step is omitted, and then the copy constructor is called directly, because the copy initialization must call the copy constructor, so the creation of ct3 is still copy initialization.

   5. ClassTest ct5 = ClassTest (); This statement is initialized for replication. First, the default constructor is called to generate a temporary object, and then the copy constructor is called with this temporary object as a parameter to construct the object ct5. So when the copy constructor becomes private, the statement won't compile.

    V. Causes of Illusions

The main reason for the above running results is the compiler's optimization, and why can I remove this illusion by declaring the copy constructor as private?

The main reason is that the copy constructor can be synthesized by default and is public. The compiler optimizes the code based on this feature. However, if you define this copy constructor yourself, the compilation will not be automatically generated. Although the compilation will not be automatically generated, if the copy constructor you defined is still public, the compilation will still do the same optimization for you. However, when it is a private member, the compiler will behave very differently, because you explicitly tell the compiler that you explicitly reject the copy operation between objects, so it will not help you do what Do the optimization, and your code will come out. For example, it is like the following statement: ClassTest ct2 = "ab"; It is used to construct the object this way: first call the constructor ClassTest (const char * pc) function to create a temporary object, and then call the copy constructor The function takes this temporary object as a parameter and constructs the object ct2.

However, the compilation also found that the copy constructor is public, that is, you explicitly told the compiler that you allow copying between objects, and at this time it found that you can call the overloaded constructor ClassTest (const char * pc) directly To directly initialize the object and achieve the same effect, so this statement is optimized to ClassTest ct2 ("ab"). If you declare the copy constructor as private, the previous copy of the object cannot be performed, that is, you cannot call the copy constructor with the temporary object as a parameter, so the compilation considers ClassTest ct2 = "ab" and ClassTest ct2 ("ab" ) Is not equivalent, it will not help you do this optimization, so the compilation error.

Note: According to the above code, some people may run different results than their own test. Why is this? As mentioned earlier, the compiler will make certain optimizations for the code, but the optimization schemes made by different compilers may be different, so when you use different compilers, because these optimization schemes do not The same, may produce different results, I use g ++ 4.7 here.
(Transfer) a big misunderstanding of C ++-in-depth explanation of the difference between direct initialization and copy initialization

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.