This article mainly introduces C + + direct initialization and replication initialization of the difference in-depth analysis, is a lot of C + + beginners need to understand the important concept, the need for friends can refer to the following
Direct initialization and replication initialization in C + + is a confusing concept for beginners, and this article tells the difference between them in an instance form. For everyone's reference. The specific analysis is as follows:
One, primer in the argument
First, let's take a look at what the classics say:
"When used with class-type objects, the replication form and the direct form of initialization are different: direct initialization calls directly to 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 is another paragraph that says:
"Usually direct initialization and replication initialization differ only on low-level optimizations, but they are fundamentally different for types that do not support replication, or when using non-explicit constructors:
?
12 |
ifstream file1( "filename" ): //ok:direct initialization ifstream file2 = "filename" ; //error:copy constructor is private” |
Ii. Common Misconceptions
From the above, we can know that the direct initialization does not have to call the copy constructor, and the copy 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:
?
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647 |
#include <iostream>
#include <cstring>
using namespace std;
class ClassTest
{
public
:
ClassTest()
{
c[0] =
‘\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"
);
//直接初始化
cout<<
"ct2: "
;
ClassTest ct2 =
"ab"
;
//复制初始化
cout<<
"ct3: "
;
ClassTest ct3 = ct1;
//复制初始化
cout<<
"ct4: "
;
ClassTest ct4(ct1);
//直接初始化
cout<<
"ct5: "
;
ClassTest ct5 = ClassTest();
//复制初始化
return 0;
}
|
The output is:
From the result of the output, we can know which functions the object's construction calls, from the comparison between Ct1 and Ct2, Ct3 and Ct4, it can be seen that Ct1 and Ct2 objects are constructed with the same function--classtest (const char *pc), the same reason, CT3 and Ct4 call 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 progress, in the end who deceived us
Many times, your own eyes tend to deceive yourself, here is an example, it is your eyes that deceive 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:
?
1234567891011121314 |
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:
?
123456 |
int main() { cout<< "ct1: " ; ClassTest ct1( "ab" ); return 0; } |
Here we can see that the original copy constructor deceived us.
Iv. Uncovering the Truth
See here, you may have been shocked, let me come to uncover the truth!
Or that sentence, what is direct initialization, and what is replication initialization?
Simply put, the definition of the object is different, one with parentheses, such as Classtest ct1 ("AB"), and an equal sign, such as classtest ct2 = "AB".
But essentially, they are fundamentally different: direct initialization directly invokes constructors that match arguments, 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. Therefore, when a copy constructor is declared as 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 the direct initialization, it does not need to call the copy constructor, directly calls the constructor classtest (const char *pc), so when the copy constructor becomes private, it can still be executed directly.
2, Classtest ct2 = "AB"; This statement is copy-initialized, which first calls the constructor classtest (const char *pc) function to create a temporary object, then calls the copy constructor, takes the temporary object as a parameter, constructs the object ct2 ; So when the copy constructor becomes private, the statement cannot be compiled through.
3, Classtest ct3 = CT1; This statement is initialized for replication, because Ct1 already exists, so you do not need to call the relevant constructor, but directly call the copy constructor, copy its value to the object ct3, so when the copy constructor becomes private, the statement cannot be compiled through.
4, Classtest Ct4 (CT1); This statement is directly initialized because Ct1 already exists, calling the copy constructor directly, generating the object ct3 the Copy object Ct4. So when the copy constructor becomes private, the statement cannot be compiled through.
Note: The 4th Object CT4 is the same as the function called by the 3rd object Ct3 creation, but I think the reason for calling the copy function is different. Because direct initialization is called by arguments to the constructor, such as Classtest Ct4 (CT1), it is directly determined to call the copy constructor classtest (const classtest& CT) based on the parameters in parentheses (an object of this class). When this is a function overload, it is a good idea to invoke the corresponding function according to the arguments when the function is called, and for CT3, it is not the same as CT4 when it is determined to invoke the copy constructor based on the arguments, only because the initialization must invoke the copy constructor. 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 copy initialization is bound to invoke the copy constructor, so the creation of CT3 is still a copy initialization.
5, Classtest ct5 = Classtest (); This statement is initialized for replication, calling the default constructor first to produce a temporary object, and then invoking 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 through.
V. Reasons for the appearance of the illusion
The main reason for the result of the above is the compiler's optimization, and why the copy constructor is declared private (privately) can be removed from this illusion? The main reason is that the copy constructor can be compiled by default and is public, and the compiler optimizes the code based on this feature. However, if you define this copy constructor yourself, compilation will not be generated automatically, although compilation will not be generated automatically, but if your own definition of the copy constructor is still public, the compilation would do the same for you. However, when it is a private member, the compiler will have a very different behavior, because you explicitly told the compiler, you explicitly rejected the copy between the objects, so it will not help you do the optimization before, your code is out of the original.
For example, just like the following statement:
?
It was supposed to construct the object: First call the constructor classtest (const char *pc) function to create a temporary object, then call the copy constructor, take the temporary object as a parameter, construct the object ct2. However, the compilation also finds that the copy constructor is public, that you explicitly tell the compiler that you are allowing replication between objects, and at this point it discovers that you can directly initialize the object by calling the overloaded constructor classtest (const char *pc) directly, and achieve the same effect, Therefore, this statement is optimized to Classtest ct2 ("AB").
If the copy constructor is declared as private, then the copy of the object cannot be made, that is, the copy constructor cannot be called as an argument, so the compilation is considered classtest CT2 = "AB" is not equivalent to Classtest ct2 ("AB"). Will not help you to do this optimization, so the compilation error.
Note: According to the above code, some people may run out of the test with the same results, which is why? As I said earlier, the compiler will do some optimizations for the code, but the different compiler's optimizations may vary, so when you use different compilers, because these optimizations are not the same, you may have different results, and I'm using g++4.7.
It is believed that this article has a certain reference function for us to study C + + program design in depth.
C + + Direct initialization and replication initialization 1