The difference between direct initialization of C + + and replication initialization deep analysis of _c language

Source: Internet
Author: User

Direct initialization and replication initialization in C + + is a very confusing concept for many beginners, and this article tells the difference between them in the form of an instance. For your reference. The specific analysis is as follows:

First, the primer in the statement

First, let's take a look at what the classics say:

"When used with class-type objects, the initialization forms differ from the direct form: direct initialization directly invokes the constructor that matches the arguments, and replication initialization always calls the copy constructor. Replication initialization first creates a temporary object with the specified constructor, and then copies the temporary object to the object being created with the copy constructor.

There is another paragraph that says:

" typically direct initialization and replication initialization differ only on low-level optimizations, however, they are intrinsically different for types that do not support replication, or for use of explicit constructors :

Ifstream file1 ("filename")://ok:direct initialization
ifstream file2 = "filename";//error:copy constructor is Private

Ii. Common Misconceptions

From the above argument, we can see that direct initialization does not necessarily call the copy constructor, and replication initialization must call the copy constructor. However, most people think that direct initialization is to invoke the copy constructor when the object is constructed, and that copying initialization is to invoke the assignment operation function (operator=) When the object is constructed, but this is a big misunderstanding. Because the initialization occurs only when an object is created, the assignment operation is not applied to the creation of the object, and primer does not. The reason for this misunderstanding may be that there is an equal sign (=) in the wording of the copy initialization.

To clarify the problem, or to explain it from the code is easier to understand, see the following code:

#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"//Copy 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 results are:

From the results of the output, we can know the structure of the object to call which functions, from Ct1 and Ct2, Ct3 and ct4 comparison, it can be seen that Ct1 and Ct2 object construction calls are the same function--classtest (const char *pc), the same reason, Ct3 and Ct4 are called the same function--classtest (const classtest& CT), and CT5 invokes the default constructor directly.

As a result, many people think that classtest ct1 ("AB") is equivalent to classtest CT2 = "AB", and classtest ct3 = Ct1; it is also equivalent to Classtest Ct4 (CT1), and none of them call the assignment action function. So they're all directly initialized, but is the truth really what you think it is? The answer is obviously not.

Third, the level of advancement, who deceived us in the end

Many times, your own eyes will often deceive yourself, here is an example, it is your eyes deceive you. Why is that? The reasons are also explained in the supplement to the optimization. Just because the compiler will help you do a lot of things you don't see, you don't know the optimization, you see the results, it is the compiler did the optimized code after the operation of the results, is not the real results of your code.

You may not believe what I say, then you can uncomment the line in the Copy function function in the class, 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, and from the results above, you might think that it was 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's a compile error, but you can also annotate the CT3 and CT4 function statements as follows:

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 there is no compilation passed. What is this for? From the above statement and the previous run results, it is true that the copy constructor has not been invoked, why is it a compile error?

After experimentation, the main function can only be compiled by:

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

Here we can see that the original copy constructor deceives us.

Iv. Uncovering the Truth

See here, you may have been frightened, below let me to uncover the truth!

Or that sentence, what is direct initialization, and what is replication initialization?

In simple terms, the definition of an object is not the same, one with parentheses, such as Classtest ct1 ("AB"), and one with an equal sign, such as classtest ct2 = "AB".

But in essence, they are fundamentally different: direct initialization directly invokes the constructor that matches the arguments, and replication initialization always calls the copy constructor. Replication initialization first creates a temporary object using the specified constructor, and then copies the temporary object to the object being created with the copy constructor. So when the copy constructor is declared private, all replication initialization is not available.

Now let's look back at the statement in the main function:

1, Classtest ct1 ("AB"); This statement belongs to direct initialization, it does not need to call the copy constructor, calls the constructor classtest (const char *pc) directly, so it can be executed directly when the copy constructor becomes private.

2, Classtest ct2 = "AB"; This statement initializes the copy, which first calls the constructor classtest (const char *pc) function to create a temporary object and then calls the copy constructor, which takes the temporary object as a parameter, constructs the object ct2 ; therefore, when the copy constructor becomes private, the statement cannot be compiled.

3, Classtest ct3 = CT1; This statement initializes the copy because Ct1 already exists, so you do not need to invoke the associated constructor, call the copy constructor directly, and copy the value to the object ct3, so when the copy constructor becomes private, the statement cannot be compiled.

4, Classtest Ct4 (CT1); This statement is for direct initialization because CT1 already exists, call the copy constructor directly, and generate the replica object ct3 of the object Ct4. So when the copy constructor becomes private, the statement cannot be compiled.

Note: The 4th Object CT4 is the same as the function called for the creation of the 3rd object Ct3, but I think the reason for calling the copy function is different. Because direct initialization invokes a constructor based on a parameter, such as Classtest Ct4 (CT1), it is directly determined to invoke the copy constructor classtest (const classtest& CT), based on the arguments in parentheses (an object of this class). When this is overloaded with functions, it is true that the corresponding function is invoked based on the parameters of the function call, and for CT3, it is not called as CT4, it is based on parameters to determine the copy constructor to invoke, simply because initialization necessarily calls the copy constructor. It is supposed to create a temporary object, but only this object already exists, so omit this step, and then call the copy constructor directly, because copy initialization is bound to invoke the copy constructor, so the creation of CT3 is still a replication initialization.

5, Classtest ct5 = Classtest (); This statement initializes the copy, starts by calling the default constructor to produce a temporary object, and then calls the copy constructor, which takes the temporary object as a parameter and constructs the object ct5. So when the copy constructor becomes private, the statement cannot be compiled.

V. The cause of false appearance

The main reason for the results above is compiler optimization, and why is the copy constructor declared private (private) to remove this illusion? The main reason is that the copy constructor can be synthesized by default and is public, and the compiler optimizes the code based on this attribute. However, if you define the copy constructor yourself, the compilation will not be generated automatically, although the compilation will not be generated automatically, but if you define the copy constructor is still public, the compilation will do the same optimization for you. However, when it is a private member, the compiler has a very different behavior because you explicitly tell the compiler that you explicitly reject the copy operation between objects, so it doesn't help you do the optimizations you've done before, and your code comes out of the way.

For example, just like the following statement:

Classtest ct2 = "AB";

It was intended to construct the object by first calling the constructor classtest (const char *pc) function to create a temporary object and then calling the copy constructor, which takes the temporary object as a parameter and constructs the object ct2. However, the compilation also finds that the copy constructor is public, that you explicitly tell the compiler that you allow replication between objects, and that at this point it finds that the object can be initialized directly by calling the overloaded constructor classtest (const char *pc) directly, and the same effect is achieved. So the statement is optimized to Classtest ct2 ("AB").

If the copy constructor is declared private, then the copy before the object cannot be used, that is, the copy constructor cannot be invoked as an argument, so the compilation thinks that classtest ct2 = "AB" and Classtest ct2 ("AB") are not equivalent, Will not help you do this optimization, so the compilation error.

Note: According to the code above, some people may run out of the same test as I do, why is this? As I said before, the compiler will make some optimizations for your code, but different compilers may have different optimizations, so when you're using a different compiler, because these optimizations don't work the same way, I'm using a g++4.7.

I believe that this article on the in-depth study of C + + program design has a certain reference role.

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.