C ++ constructor call and object creation

class Test{ public : int x; Test() { x = 0; cout<<"constructor with no arguments called"<<endl; } Test(int xx) { x = xx; cout<<"constructor with single int argument called"<<endl; } }; int main() { Test a(10); Test aa = 10; } 

Exit: Software Compilation and Exits

a constructor with a single int argument called

a constructor with a single int argument called

But now

 class Test{ public : int x; Test() { x = 0; cout<<"constructor with no arguments called"<<endl; } Test(int xx) { x = xx; cout<<"constructor with single int argument called"<<endl; } Test( Test& xx) { x = xx.x; cout<<"copy constructor called"<<endl; } }; int main() { Test a(10); Test aa = 10; } 

cannot compile.

 constructorinvokings.cc:36:7: error: no viable constructor copying variable of type 'Test' Test aa = 10; ^ ~~ constructorinvokings.cc:23:3: note: candidate constructor not viable: no known conversion from 'Test' to 'Test &' for 1st argument Test( Test& xx) ^ 1 error generated. 

I am new to C ++.

Do not check a (10) and check aa = 10; are identical?

Why is adding a copy constructor contrary to Test aa = 10?

if I change Test (Test & amx; xx) to Test (const Test & amx; xx), it works. But why does the compiler verify the signature of the copy constructor when we try to call the constructor with an integer argument.

Please clarify

Thanks in advance.

+4
source share
4 answers

All the answers you have received so far are too complicated and / or a bit misleading.

In the first construct / initialization:

 T a(10); 

Absolutely obvious thing. More interesting is the second construct / initialization:

 T aa = 10; 

This is equivalent to:

 T aa(T(10)); 

The value is that you create a temporary object of type T, and then create aa as a copy of this temporary. This means that the copy constructor is being called.

C ++ has a default copy constructor, which it creates for the class if you don't have it explicitly declared. So, although the first version of class T does not have a declared constructor, there is still one. The one that the compiler declares has this signature T(const T &) .

Now in the second case, when you declare what looks like a copy constructor, you make the argument a T & , not const T & . This means that the compiler, when trying to compile the second expression, tries to use your copy constructor, and it cannot. He complains that the copy constructor you created requires a non-constant argument, and the argument you are given is const. So it fails.

Another rule is that after the compiler has converted your initialization to T aa(T(10)); , then it is allowed to convert it to T aa(10); . This is called a "copy of elite." In some cases, the compiler allows skipping calls to the copy constructor. But he can do this only after he checks the correctness of the expression formation and does not create any compiler errors when the copy constructor call still exists. Thus, this is an optimization step that can affect which parts of the program are executed, but cannot affect which programs are valid and which of them are erroneous (at least from the point of view of whether they are compiled or not) .

+6
source

Test a (10) and test aa = 10; not identical. The first of them creates a test of 10, and the second - a test of 10 and then copies aa from it. Adding a conflicting constructor conflicts because it states that create-copy is a mutable operation for both operands. There are times when copy-constructors take the source code as a non-const link, but they are somewhat complicated cases and this is not your case.

Edit: Note that in the second case, the compiler is allowed to exclude this copy-construct and usually does so.

+4
source

(A less detailed test is here .)

The two forms of initialization are actually not completely equivalent.

The first is your standard swamp design:

 T o(10); 

The latter, however, is more complicated.

 T o = 10; 

Here the expression in RHS ( 10 ) is converted to type T , then the object o copied from this converted expression. A copy construct is not possible here because your T(T&) forbids the synthesis of an implicit T(T const&) , and the temporary RHS object cannot be bound to ref-to-non const .

Now the compiler is allowed to exclude this copy-construct, and this usually happens, but the conversion must remain valid or the program is poorly formed.


[n3290: 8.5/13]: The initialization form (using parentheses or =) is usually negligible, but it matters when the initializer or the object being initialized has the class type; See below. [..]

[n3290: 8.5/14]: Initialization that occurs in the form

 T x = a; 

and also when passing arguments, returning a function, throwing an exception (15.1), handling the exception (15.3) and the aggregate member initialization (8.5.1) is called copy-initialization. [Note: Copy-initialization may cause a move (12.8). -end note]

[n3290: 8.5/16]: semantics of initializers is as follows. [..] If the destination type is a (possibly cv-qualified) class of type: [..] Otherwise (that is, for the rest of the copy initialization cases ), custom conversion sequences that can convert from source type to destination type or (when the conversion function is used), its derived class is listed as described in 13.3.1.4 , and the best one is selected using overload resolution (13.3). If the conversion cannot be performed or is ambiguous, the initialization is poorly formed. [..]

[n3290: 12.8/31]: When certain criteria are met, an implementation is allowed to omit the instance construct / move of the class object, even if the copy / move constructor and / or destructor for the object have side effects. [..] This permission of copy / move operations, called a copy, is permitted in the following circumstances (which may be used to eliminate multiple copies): [..]

  • when a temporary class object that is not attached to a link (12.2) is copied / transferred to a class object with the same cv-unqualified type, the copy / move operation can be omitted from building the temporary object directly to the target, copy / move is skipped. [..]

(I cannot find a quote that explicitly states that the copy constructor should be available even when the copy is complete, but it is.)

+2
source

I do not agree with K-ballo. When you define c'tor with a single argument, it can be [incorrectly] used by the compiler for implicit conversion. What happens in this case.

So when you run the program, it calls "c'tor with one argument" to build AWA aa.

Test aa = 10;

There is no โ€œcopyโ€ or โ€œassignmentโ€ in this statement. Given that you provided the compiler with a single arg c'tor, in this case it would use [mis].

 // So basically compiler converts this: Test aa = 10; // to Test aa(10); 

You can stop the abuse by noting that c'tor is explicit. Just change Test( int x ) to explicit Test( int x ) . See some explanations of the explicit keyword here: What does the explicit keyword mean in C ++?

if I change Test (Test & amx; xx) to Test (const Test & amx; xx), it works. But why does the compiler verify the signature of the copy constructor when we try to call the constructor with an integer argument.

I also did not understand this and would like to know. :)

I noticed that a copy of c'tor is simply never called.

 #include<iostream> using namespace std; class Test { public : int x; Test() { x=0; cout << " Test() - " << x << endl;} Test(int xx) { x=xx; cout << " Test(int xx) - " << x << endl;} Test(Test& xx){ x=xx.x; cout << " Test(Test& xx) - " << x << endl;} Test(const Test& xx){ x=xx.x; cout << " Test(const Test& xx) - " << x << endl;} Test& operator= (const Test& xx) { x=xx.x; cout << " Test& operator= (const Test& xx) - " << x << endl; return *this;} }; int main() { cout << "--Test a(10);--" << endl; Test a(10); cout << "--Test aa = 20;--" << endl; Test aa = 20; cout << "--Test aaa = aa;--" << endl; Test aaa = aa; cout << "--aaa = aa;--" << endl; aaa = aa; cout << "--aaa = 30;--" << endl; aaa = 30; } /* OUTPUT: --Test a(10);-- Test(int xx) - 10 --Test aa = 20;-- Test(int xx) - 20 --Test aaa = aa;-- Test(Test& xx) - 20 --aaa = aa;-- Test& operator= (const Test& xx) - 20 --aaa = 30;-- Test(int xx) - 30 Test& operator= (const Test& xx) - 30 */ 

and when compiling c'tor with const arg Test(const Test& xx) commented out:

We get compilation errors.

 D:\Workspaces\CodeBlocks\Test\main.cpp: In function 'int main()': D:\Workspaces\CodeBlocks\Test\main.cpp:21:19: error: no matching function for call to 'Test::Test(Test)' D:\Workspaces\CodeBlocks\Test\main.cpp:10:9: note: candidates are: Test::Test(Test&) D:\Workspaces\CodeBlocks\Test\main.cpp:9:9: note: Test::Test(int) D:\Workspaces\CodeBlocks\Test\main.cpp:8:9: note: Test::Test() Process terminated with status 1 (0 minutes, 0 seconds) 4 errors, 0 warnings 

Line 21 Test aa = 20;

-1
source

All Articles