Behaviour of copy constructor accepting const reference - c++

In the following Code, in this line
A(A& b)
When using this compiler gives error as
c110.cpp:41: error: no matching function for call to ‘A::A(A)’
c110.cpp:8: note: candidates are: A::A(A&)
But as soon as i convert it into
A(const A& b)
Many many thanx in Advance
No error comes. Why is it so?
Code
class A
{
public:
static int cnt;
A(A& b)
{
cnt++;
cout<<"cnt="<<cnt<<endl;
}
A()
{
cnt++;
cout<<"cnt="<<cnt<<endl;
}
~A()
{
cnt--;
cout<<"cnt="<<cnt<<endl;
}
};
int A :: cnt=0;
A fun(A b)
{
return b;
}
int main()
{
A a;
A b=fun(a);
return 0;
}

Non-const references cannot bind to temporaries. If you pass a temporary as parameter, A& is illegal but const A& isn't.
The line
A b=fun(a);
does copy-initialization on the object returned by fun(a), which is a temporary.
Also, the copy constructor shouldn't take a non-const reference because, logically, you don't need to modify the object you're copying from.

I think its always safe to use A(const A&) type of syntax for copy construction rather than A(A&), because RVO may take place or not, its compiler dependent.
As in the above question RVO is not taking place and the temporary is been created, hence A(const A&) is safe to use.

Related

Const ref versus const pointer as a data member for operator= overloading

A class with a 'const int&' data member causes the following compilation error when overloading operator= (compiler is g++):
assignment of read-only location.
When the data member is changed to 'const int*', it is fine.
Why?
#include <iostream>
using namespace std;
class B {
private:
const int& ir;
//const int* ir;
public:
B(const int& i) : ir(i) {}
//B(const int& i) : ir(&i) {}
B& operator=(B& b) { ir = b.ir; return *this; }
};
g++ error message:
opertostack.cpp:9:31: error: assignment of read-only location ‘((B*)this)-> B::ir’
B& operator=(B& b) { ir = b.ir; return *this; }
^~
You cannot rebind references. Once they are created, they need to refer to the same object for their entire lifetime.
However, your code has much bigger issues. Let's just remove operator=() so it compiles. We then instantiate a B:
B b(42);
b.ir was bound to the temporary int passed to the constructor. That temporary doesn't exists anymore after the constructor returns. b.ir is now a dangling reference. It refers to an object that does not exist anymore.
A pointer isn't going to help you either. If we change B::ir to be a const int* and switch the commented out code, then the result of instantiating a B as above is now a dangling pointer. It points to a temporary that doesn't exist anymore.
So in both cases, you get undefined behavior when using B::ir.
What you want here is just a normal int member. The constructor parameter doesn't need to be a reference either in this case. An int is just as easy to copy as a reference so you don't gain anything by using a reference parameter. Finally, the assignment operator should take a const reference, so that you can assign from const B objects as well:
class B {
private:
int ir;
public:
B(const int& i) : ir(i) {}
B& operator=(const B& b) { ir = b.ir; return *this; }
};

Confusion about Copy Constructor in C++

Code:
class A
{
public:
A()
{
cout<<"Defualt Constructor"<<endl;
}
A(A &t)
{
cout<<"Copy Constructor"<<endl;
}
};
A func()
{
cout<<"In func"<<endl;
}
int main()
{
A a1;
A a2;
a2 = func();
return 0;
}
The program works fine. Also, If I call function like this:
A a2 = func();
and add const qualifier in copy constructor argument like:
A(const A &t)
{
cout<<"Copy Constructor"<<endl;
}
Also, working fine.
But, If remove const from copy constructor argument like:
A(A &t)
{
cout<<"Copy Constructor"<<endl;
}
and call function func()
A a2 = func();
Compiler giving an error:
error: invalid initialization of non-const reference of type 'A&' from an rvalue of type 'A'
A a2 = func();
^
prog.cpp:13:9: note: initializing argument 1 of 'A::A(A&)'
A(A &t)
^
Why does compiler give an error in last case?
A a2 = func(); is copy initialization, a2 will be initialized from the object returned by func() via copy constructor. func() returns by value, so what it returns is a temporary, which can't be bound to lvalue-reference to non-const (i.e. A &), that's why you get the error.
Temporary could be bound to lvalue-reference to const (or rvalue-reference), so changing the parameter type to const A &t (or adding move constructor) would make it work fine.
BTW: a2 = func(); has nothing to do with copy constructor, but copy assignment operator. You didn't declare it for A, and the implicitly declared copy assignment operator takes const A& as parameter, then it's fine.
BTW2: func() returns nothing. Note that flowing off the end of a non-void function without returning leads to UB.

Why does the compiler choose the copy ctor after calling move

For the following code, I know that because I implement a copy constructor the default move is blocked by the compiler, what I don't understand is why the compiler choose the copy constructor, and not issuing an error?
Can a rvalue reference be the parameter for a reference function if no rvalue ref function exists?
If not, what do happens here?
#include <iostream>
using namespace std;
class A{
public:
A(){printf("constructor\n");}
A(const A& a){printf("copy constructor");}
};
int main()
{
A a;
A b = std::move(a);
return 1;
}
The output is:
constructor
copy constructor
Thanks
The reason is that rvalue expressions can be bound to function parameters that are const lvalue references.
Also note that const rvalue expressions cannot be bound to rvalue references:
class A{
public:
A(){printf("constructor\n");}
A(const A& a){printf("copy constructor");}
A(A&&) = default; // <-- has move ctor
};
int main()
{
const A a; // <-- const!
A b = std::move(a); // <-- copy not move!!!
return 1;
}
The code above still calls the copy constructor, even though there is a move constructor.
std::move will take your named value and turn it into an rvalue expression, nothing more.
And, just like for any other rvalue, if it can't be moved, it'll be copied.
An rvalue of type T can be bound to a const T& just fine.

Error: no matching function for call to 'A::A(A)'

I have coded a very basic class
class A
{
int n;
public:
A(int& val){val=n;}
A(const int& val=0){n=val;}
A(A& val){n=val.n;}//work without this constructor
};
int main()
{
A a=3;//want to call A::A(const int&)
return 0;
}
I don't want to create a constructor with a copy from an instance of A (for a future use)
What's wrong with this simple code?
Error message :
...\main.cpp||In function 'int main()':|
...\main.cpp|16|error: no matching function for call to 'A::A(A)'|
...\main.cpp|16|note: candidates are:|
...\main.cpp|11|note: A::A(A&)|
...\main.cpp|11|note: no known conversion for argument 1 from 'A' to 'A&'|
...\main.cpp|10|note: A::A(const int&)|
...\main.cpp|10|note: no known conversion for argument 1 from 'A' to 'const int&'|
...\main.cpp|9|note: A::A(int&)|
...\main.cpp|9|note: no known conversion for argument 1 from 'A' to 'int&'|
||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
It seems 3 is considered as an instance of A?
If I add A(const A& val){n=val.n;}
the constructor A(const int&) is chosen.
What can I do to compile successfully without A(const A& val)?
The issue is your copy constructor: A(A& val) { n=val.n; }.
Given this line A a = 3; one possibility is to use A a = A(3) which in turn will use the copy constructor. However, it is against the standard to bind a temporary to non-const. A proper copy constructor will solve the problem.
Example Code
#include <iostream>
class A
{
int n;
public:
A(int& val) : n(val) { std::cout << "A(int&)\n"; }
A(const int& val=0) : n(val) { std::cout << "A(const int&)\n"; }
A(const A& val) : n(val.n) { std::cout << "A(const A&)\n"; }
};
int main()
{
A a = 3;
return 0;
}
Example Output
A(const int&)
Live Example
Note:
The above code makes proper use of the initialization lists
The output shows the copy constructor is not actually invoked
The line of code;
A a = 3;
Is using copy initialisation to work. For that to work, a copy of A is needed and is duly made. You have two constructors taking an int as an argument (and neither are explicit).
The copy cannot bind to A(A& val) because normal references don't bind to temporary values.
Possible solutions, direct initialisation;
A a { 3 };
Add or change the copy constructor to a move constructor;
A(A&& val);
Add a const to the copy constructor (although this is not what you wanted, but it does work);
A(A const& val);
Note both clang and g++ reject the original code correctly, but VC++ accepts it.
In this statement
A a=3;//want to call A::A(const int&)
there is created a temporary object of type A using constructor
A(const int& val=0){n=val;}
However a temporary object can be bound to a constant reference. So the compiler need that the copy constructor
A( const A& val){n=val.n;}//work without this constructor
^^^^^
would be at least accessible (even if it will not be called due to the copy constructor elision).
But the class does not has this constructor and the compiler issues an error.
On the other hand when you comment this constructor then the compiler itself implicitly defines this constructor and the code is compiled.
Take into account that this constructor
A(int& val){val=n;}
^^^^^^
does not make sense.:)

Constructor overloading chooses cast operator instead of struct type

I've encountered a weird situation where the compiler chooses to cast a structure even though there's a perfectly good constructor that receives the structure type.
A small example:
struct A
{
operator int() {return 1;}
};
struct B
{
B(A& a) { OutputDebugStringA("A constructor\n"); }
B(int i) { OutputDebugStringA("int constructor\n"); }
};
A test () { A a; return a;};
int _tmain(int argc, _TCHAR* argv[])
{
B b(test());
return 0;
}
Explanation: A has a cast operator to int. B has 2 overloaded constructors, one that accepts A reference, and one that accepts int.
Function test() returns an A object.
For some reason, the compiler decides to cast the return value to an int, and use the constructor that accepts an int. int constructor
Can anyone explain why this happens ? I have a few theories, but I would like an answer that is based on something real (maybe a quote from the standard).
Note:
I can get the expected result (constructor that accepts the type) by changing the constructor signature to: B(const A& a) or B(A&& a)
Your constructor takes a non-const reference to A, which cannot bind to a temporary. You pass it a temporary here:
B b(test());
// ^^^^^^ temporary A
so the only valid constructor is the one taking an int. You can change this behaviour by making the relevant constructor take a const reference:
B(const A& a) { OutputDebugStringA("A constructor\n"); }
//^^^^^
and similarly for B(A&& a); in C++11.
Alternatively, keeping the original constructor signature and passing an lvalue also results in the constructor call:
A a;
B b(a);