这篇文章上次修改于 664 天前,可能其部分内容已经发生变化,如有疑问可询问作者。
Type of Class Constructor
There are 4 general type of constructor.
- Constructor
- Default Constructor
- Copy Constructor
- Delegate Constructor
- Move Constructor
Default Constructor
Default Constructor is a class constructor has no parameter.
You could explicitly declare a default constructor for a class like below:
class CustomClass
{
public:
CustomClass() // default constructor
{
// do something here
}
}Compiler will automatically generate a default constructor if all following condition met:
- No any other constructor.
- No explicit
deleteof the default constructor.
Prevent Default Constructor Auto-generate
If you want to explicitly tell compiler you don't need a default constructor, you can use delete keyword.
CustomClass() = delete;Then when you try to create a new instance by calling the default constructor, you will receive compliant by compiler.
CustomClass instance; // Error: the default constructor of "CustomClass" cannot be referenced -- it is a deleted functionCopy Constructor
Copy Constructor will be called when you try to create a new instance of this class based on the data of an existing instance.
When will be called
More detailed, copy constructor will be called in following cases:
- Creating new instance from existing one.
- Passing class instance as a function parameter by value.
- Return a class instance. (Not really in morden compiler, we will talk more about this in the move constructor part)
CustomClass a; // default constructor called
CustomClass b(a); // copy constructor called
CustomClass c = a; // copy constructor called
void some_func(CustomClass ins);
some_func(c); // copy constructor calledMove Constructor
To be simple, move constructor will be called when construct a new instance from an existing rValue (temporary) instance.
If you don't know what is lValue and rValue , then you need to figure it out first before continue learning about move constructor.
Check example below:
class CustomClass;
CustomClass a;
CustomClass b = std::move(a); // move constructor calledThe example is simple, std::move(a) turns a into a rValue .
RVO (Return Value Optimization)
Morden C++ compiler has done a great work to try to reduce the times we call copy constructor.
CustomClass some_func(CustomClass ins) // ins1 in main has been copyed to local variable ins here
{
ins.id++;
CustomClass tmpIns = ins; // copy constructor called: ins -> tmpIns
tmpIns.id++;
return tmpIns; // copy/move assignment operator called: tmpIns -> ins2 (in main),
// you can simply consider this equals ins2(in main) = tmpIns (in some_func)
}
int main()
{
// CustomClass instance;
CustomClass ins1(1); // constructor called
CustomClass ins2; // default constructor called
ins2 = some_func(ins1); // copy constructor called: ins1 -> ins(local in some_func)
cout << ins2.id;
return 0;
}Output of the code above is:
Constructor Called
Default Constructor Called
Copy Constructor Called: existId: 1
Copy Constructor Called: existId: 2
Copy/Move Assignment Operator Called: existId: 3
3existIdhere means theidof the instance that being copied.idis ainttype member variable of this class.
The last line:
Copy/Move Assignment Operator Called: existId: 3This means if this class has an move assignment operator, then move assign will be used, otherwise, copy assignment will be used.
Let's see another example:
CustomClass some_func(CustomClass ins)
{
ins.id++;
CustomClass tmp = CustomClass(ins); // Copy Constructor Called: ins->tmp
CustomClass tmp2 = tmp; // Copy Constructor Called: tmp->tmp2
return tmp2; // do nothing, since tmp2 actually use the addr of ins3
}
int main()
{
// CustomClass instance;
CustomClass ins1(1); // Constructor Called
CustomClass ins3 = some_func(ins1); // Copy Constructor: ins1 -> ins (local in some_func)
return 0;
}Output:
Constructor Called
Copy Constructor Called: existId: 1
Copy Constructor Called: existId: 2
Copy Constructor Called: existId: 2So based on above experiment we know, morden C++ compiler will do more than we expected.
Receiving Variable Created Before Function Return
If the receiving variable (for example ins2 = some_func(ins1);, then ins2 is the receiveing variable here) has been created already when function return, then function will try to call move assignment operator first, if no such operator, then compiler will try calling copy assignment operator .
Receiving Variable Not Created Before Function Return
If the receiving variable not been created, then the return value and the receiving value is actually a same instance! You don't even need to move them. For example in second example, tmp2 created in some_func() is actually use the same address of ins3 in main() function.
In this situation, the allocation of memory is done by original calling function (In the second example, that is main() is responsible to find a place in memory which will be used to store ins3 in main, a.k.a.: tmp2 in some_func(), they are the same thing in this example). However main() is not responsible to initialize this memory, some_func() is responsible to initialize a new CustomClass instance on this memory. Check the diagram below:

没有评论