class Sample
{
public:
Sample();
Sample(int i);
Sample(Sample& s);
~Sample();
};
Sample::Sample()
{
cout<<"Default constructor called\n";
}
Sample::Sample(int i)
{
cout<<"1-argument constructor called\n";
}
Sample::Sample(Sample& s)
{
cout<<"Copy constructor called\n";
}
Sample::~Sample()
{
cout<<"Destructor called\n";
}
void Fun(Sample s)
{
}
int main()
{
Sample s1;
Fun(5);
return 0;
}
I expected an implicit conversion of 5.
But, When I compile the above code, I get following error:
main.cpp:7:8: error: no matching function for call to ‘Sample::Sample(Sample)’
main.cpp:7:8: note: candidates are:
Sample.h:10:3: note: Sample::Sample(Sample&)
Sample.h:10:3: note: no known conversion for argument 1 from ‘Sample’ to ‘Sample&’
Sample.h:9:3: note: Sample::Sample(int)
Sample.h:9:3: note: no known conversion for argument 1 from ‘Sample’ to ‘int’
Sample.h:8:3: note: Sample::Sample()
Sample.h:8:3: note: candidate expects 0 arguments, 1 provided
Helper.h:6:13: error: initializing argument 1 of ‘void Fun(Sample)’
What is the problem? When i remove the copy constructor, the above code compiles successfully.
Thanks in advance.
Temporaries cannot bind to non-const references. Your copy constructor should be:
Sample::Sample(const Sample&)
Removing it tells the compiler to generate a trivial one, which will have the above signature.
Related
struct Alien {
int id;
char const* name;
Alien() = default;
Alien(int id, char const* name) : id{id}, name{name} {}
Alien(int id): id{id} {}
};
struct Spaceship {
Alien alien1;
Spaceship() = default;
Spaceship(Alien const& z) {}
Spaceship(Spaceship const& other) = default;
Spaceship(Spaceship&& other) = default;
};
int main()
{
Spaceship s1(3433); // works
Spaceship s2(2322, "Kronas"); // error
}
source>:55:14: error: no matching constructor for initialization of 'Spaceship'
Spaceship s(2322, "Kronas");
^ ~~~~~~~~
<source>:45:5: note: candidate constructor not viable: requires single argument 'z', but 2 arguments were provided
Spaceship(Alien const& z) { }
^
<source>:46:5: note: candidate constructor not viable: requires single argument 'other', but 2 arguments were provided
Spaceship(Spaceship const& other) = default;
^
<source>:47:5: note: candidate constructor not viable: requires single argument 'other', but 2 arguments were provided
Spaceship(Spaceship&& other) = default;
^
<source>:44:5: note: candidate constructor not viable: requires 0 arguments, but 2 were provided
Spaceship() = default;
^
1 error generated.
Execution build compiler returned: 1
The std says that in direct initialization an implicit conversion to one of the T argument's constructor is applicable.
Why the second initialization with two arguments throws an error?
None of Spaceship constructors accepts two arguments. That is why it throws an error when you give it two. There should be something like:
Spaceship(int number, char const* name){
alien1.id = number;
alien1.name = name;
};
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.:)
I have this code in C++:
#include <iostream>
class Object
{
public:
Object();
Object(int someValue = 0);
private:
int value;
};
Object::Object()
{
std::cout << "No argument constructor" << std::endl;
value = 0;
}
Object::Object(int someValue)
{
std::cout << "Argument constructor" << std::endl;
value = someValue
}
int main()
{
Object obj1; // should call Object() (according to me)
Object obj2(5); // should call Object(int) (according to me)
}
But the compiler (MinGW 4.8.1) on Windows 7 64 bit, complains about a call of overloaded 'Object()' being ambiguous:
defaultConstructorTest.cpp: In function 'int main()':
defaultConstructorTest.cpp:27:9: error: call of overloaded 'Object()' is ambiguous
Object obj1;
^
defaultConstructorTest.cpp:27:9: note: candidates are:
defaultConstructorTest.cpp:19:1: note: Object::Object(int)
Object::Object(int someValue)
^
defaultConstructorTest.cpp:13:1: note: Object::Object()
Object::Object()
^
So ideally, I would like to get this output:
No argument constructor
Argument constructor
This is because call to
Object obj1;
is ambiguous. As second constructor has one default argument which makes it a good enough contender for default construction of objects.
Suppose I have the following (very rough) code
class foo
{
public:
int a;
foo() //Regular constructor
{
......
std::cout << "Regular \n";
}
foo(foo& f) //Copy constructor with with non-const parameter
{
....
std::cout << "Copy Constructor \n" ;
}
foo& operator= (const foo& f)
{
std::cout << "Copy Assignment Operator \n" ;
return *this;
}
};
foo makeFoo()
{
return foo();
}
int main()
{
foo a = makeFoo();
}
Now when attempting to simulate this code with the -fno-elide-constructors (for experimental and educational purpose) I get the following errors
main.cpp: In function 'foo makeFoo()':
main.cpp:32:15: error: no matching function for call to 'foo::foo(foo)'
return foo();
^
main.cpp:32:15: note: candidates are:
main.cpp:12:5: note: foo::foo(foo&)
foo( foo& f)
^
main.cpp:12:5: note: no known conversion for argument 1 from 'foo' to 'foo&'
main.cpp:10:5: note: foo::foo()
foo() { std::cout << "Regular \n";}
^
main.cpp:10:5: note: candidate expects 0 arguments, 1 provided
main.cpp: In function 'int main()':
main.cpp:40:20: error: no matching function for call to 'foo::foo(foo)'
foo a = makeFoo(); //Move constrcutor - Move Constructor or with copy elision only regular constrcutor
^
main.cpp:40:20: note: candidates are:
main.cpp:12:5: note: foo::foo(foo&)
foo( foo& f)
^
main.cpp:12:5: note: no known conversion for argument 1 from 'foo' to 'foo&'
main.cpp:10:5: note: foo::foo()
foo() { std::cout << "Regular \n";}
^
main.cpp:10:5: note: candidate expects 0 arguments, 1 provided
main.cpp: In function 'foo makeFoo()':
main.cpp:33:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
Now these errors are resolved by making the parameter of the copy constructor a const type. I wanted to know if my understanding of why making the parameter of the copy constructor a const type fixes this problem. Please let me know if my understanding or reasoning is incorrect. Now in the method makeFoo after the execution of the statement return foo(); regular constructor of foo is called. Then the copy constructor of foo is called. Now in my code I have something like this:
foo a = makeFoo();
In this case the copy constructor of the foo a is called. since the return type of makeFoo() is an rvalue which is always a constant and the copy constructor of foo is a non-const thus an error is generated as we are attempting to pass a constant reference type to a non-constant reference type.
As you mentioned, in your expression foo a = makeFoo(); makeFoo() is an rvalue.
Constructor with non-const input parameter (your case) can only bind lvalue. In fact, makeFoo() returns a temporary objects created by the compiler, and the compiler doesn't want you to modify this temporary object that can be deleted at any moment. So the compiler will throw an error when you try to pass an rvalue to a constructor with non-const input parameter.
Constructor with const input parameter can bind rvalue and lvalue.
Here is my code below:
template<class t>
class smart_ptr{
t *ptr;
public:
smart_ptr(t *p):ptr(p){cout<<"smart pointer copy constructor is called"<<endl;}
smart_ptr(const smart_ptr &sm){cout<<"copy constructor is called"
<<endl;ptr=sm->ptr;}
~smart_ptr(){cout<<"smart pointer destructor is called"<<endl;delete(ptr);}
t& operator *(){cout<<"returning the * of pointer"<<endl;return(*ptr);}
t* operator ->(){cout<<"returning the -> of pointer"<<endl;return(ptr);}
t& operator=(const t &lhs){ptr=lhs->ptr;cout<<"assignement operator called"
<<endl;return *this;}
};
class xxx{
int x;
public:
xxx(int y=0):x(y){cout<<"xxx constructor called"<<endl;}
~xxx(){cout<<"xxx destructor is called"<<endl;}
void show(){cout<<"the value of x="<<x<<endl;}
};
int main(int argc, char *argv[])
{
xxx *x1=new xxx(50);
smart_ptr<xxx> p2(new xxx(60));
smart_ptr<xxx> p1(x1);
p1->show();
smart_ptr<xxx> p3(p2); //calling copy construcotr is giving error
p3=p1; //calling assignment operator is giving error
p2->smart_ptr<class xxx>::~smart_ptr<class xxx>(); //calling smart pointer
destructor gives error
return 0;
}
I am getting compilation errors while compiling this file because of wrong copy constructor, assignment operator and destructor codes.
The errors are:
smart_pointer_impl.cpp: In function ‘int main(int, char**)’:
smart_pointer_impl.cpp:33: error: ‘smart_ptr<xxx>’ is not a base of ‘xxx’
smart_pointer_impl.cpp: In copy constructor ‘smart_ptr<t>::smart_ptr(const
smart_ptr<t>&) [with t = xxx]’:
smart_pointer_impl.cpp:28: instantiated from here
smart_pointer_impl.cpp:8: error: passing ‘const smart_ptr<xxx>’ as ‘this’ argument
of ‘t*
smart_ptr<t>::operator->() [with t = xxx]’ discards qualifiers
smart_pointer_impl.cpp:8: error: ‘class xxx’ has no member named ‘ptr’
Please find where I am wrong in the above functions. Any help is welcome.
One obvious error is that your assignment operator should take and return references to smart_ptr, not t:
smart_ptr& operator = (const smart_ptr& lhs)
//^^^^^^^^^ ^^^^^^^^^
Next, your copy constructor calls sm->ptr when it should be calling sm.ptr, since -> has been overloaded to return a t anyway:
smart_ptr(const smart_ptr& sm) : ptr(sm.ptr) { .... }
Compilation errors could be fixed with the following changes:
// copy ctor
smart_ptr(const smart_ptr &sm)
: ptr(sm.ptr)
{
cout<<"copy constructor is called" << endl;
}
// destructor's invocation
p2.~smart_ptr();
However there's a logic error in the copy constructor as the underlying object will be deleted twice (or more times).