Why cant i call 'explicit C(const C&)'? - c++

Heres the link to code and the error
I dont understand why the line return (const C&)cc; doesnt work.
Heres a paste of code and error
#include <stdio.h>
class C
{
public:
int i;
explicit C(const C&) // an explicit copy constructor
{
printf("\nin the copy constructor");
}
explicit C(int i ) // an explicit constructor
{
printf("\nin the constructor");
}
C()
{
i = 0;
}
};
class C2
{
public:
int i;
explicit C2(int i ) // an explicit constructor
{
}
};
C f(C c)
{ // C2558
// c.i = 2;
// return c; // first call to copy constructor
C cc;
return (const C&)cc;
}
void f2(C2)
{
}
void g(int i)
{
// f2(i); // C2558
// try the following line instead
f2(C2(i));
}
int main()
{
C c, d;
d = f(c); // c is copied
}
Output:
In function 'C f(C)': Line 36: error:
no matching function for call to
'C::C(const C&)' compilation
terminated due to -Wfatal-errors.

Line 36 requires a implicit call of the copy constructor, which you have declared explicit for some reason.
Remove the explicit on the copy and you will be fine.
It makes sense to have it on C::C(int).

Examples of calling the explicit copy-constructor:
http://ideone.com/bV4S7
http://ideone.com/G0OYi
Of course, pass-by-value and return-by-value always call the copy constructor implicitly, so declaring the copy constructor explicit will prevent this (not necessarily a bad thing).

Try:
return C(cc);
This is an explicit call to the copy constructor. Casting to a reference is not.

Related

class constructor matching, why didn't the move constructor called here?

I'm recently learning about move constructor, and I met a strange problem.
I have the following code:
#include <iostream>
class a
{
public:
a() { printf("default\n"); }
a(const a& aa) { printf("const lr\n"); }
a(a& aa) { printf("lr\n"); }
a(a&& aa) { printf("rr\n"); }
a(const a&& aa) { printf("const rr\n"); }
};
a foo()
{
return a();
}
void func(a& a) {
printf("func lr\n");
}
void func(a&& aa) {
printf("func rr\n");
}
int main()
{
printf("a1: ");a a1;
printf("a2: ");a a2(a1);
printf("a3: ");a a3(std::move(a2));
printf("a4: ");a a4(foo());
printf("a5: ");a a5(std::move(foo()));
func(foo());
}
The output is:
a1: default
a2: lr
a3: rr
a4: default
a5: default
rr
default
func rr
All is good except for a4. I expect that the return type of foo() is a rvalue. I think the call of func() at last has proved that. So why doesn't the move constructor called when constructing a4? And at the same time, it is called when constructing a5.
That's probably because of copy_elision.
Under the following circumstances, the compilers are required to omit
the copy- and move- construction of class object:
In initialization, if the initializer expression is a prvalue and the cv-unqualified version of the source type is the same class as the class of the destination, the initializer expression is used to initialize the destination object:
T x = T(T(T())); // only one call to default constructor of T, to initialize x
In a function call, if the operand of a return statement is a prvalue and the return type of the function is the same as the type of that prvalue:
T f() { return T{}; }
T x = f(); // only one call to default constructor of T, to initialize x
T* p = new T(f()); // only one call to default constructor of T, to initialize *p
Your situation falls under the second case.

C++ error received

I have this code:
i receive next error: A::A(int) candidate expect 1 argument, 0 provided but I cannot understand what the problem is.
#include <iostream>
using namespace std;
class A
{
int x;
public:
A(int i):x(i) {}
int get_x() const {return x;}
};
class B:public A
{
int *y;
public:
B(int i):A(i) {y=new int[i]; for(int j=0;j<i;j++) y[j]=1;}
B(B&);
int &operator[] (int i) {return y[i];}
};
B::B(B&a)
{
y=new int[a.get_x()];
for(int i=0;i<a.get_x();i++) y[i]=a[i];
}
ostream& operator<<(ostream& o, B a)
{
for(int i=0;i<a.get_x();i++) o<<a[i];
return o;
}
int main()
{
B b(5);
cout<<b;
return 0;
}
Because A does not have a constructor that takes 0 arguments you need to explicitly call the constructor with arguments provided from any class constructor that inherits from A, which is B in this case.
In your first constructor:
B(int i):A(i) {y=new int[i]; for(int j=0;j<i;j++) y[j]=1;}
You are doing this well by calling A(i).
But in your second constructor:
B::B(B&a)
{
y=new int[a.get_x()];
for(int i=0;i<a.get_x();i++) y[i]=a[i];
}
There is no call to A's constructor and thus you get an error since the compiler doesn't know how to create an A object, you probably meant to do :
B::B(B&a) : A(a.get_x())
{
y=new int[a.get_x()];
for(int i=0;i<a.get_x();i++) y[i]=a[i];
}
Your second B constructor B::B(B&a) implicitly tries to construct the base class A using its default constructor, which is not defined.
You may explicitly call the A(int) constructor, i.e.:
B::B(B&a)
: A(a.get_x())
{
...
The problem is that when you declare an object of type B you also sort need to construct an instance of A.
In B::B(B&a) you do not explicitly call any constructor for A, so the compiler try to call the one with no parameters A::A(), but it fails since it is not declared.
You have to either declare a A::A() in A or explicitly call one of the available constructors in A from B's constructror.
Note that A::A() could be automatically generated by the compiler, and is called default constructor. Read more about it here

Initializing A Variable With Its Default Constructor

Question:
Is there a difference between the following initializations?
(A) What exactly is the second one doing?
(B) Is one more efficient than the other?
int variable = 0;
int variable = int();
This question also applies to other data types such as std::string:
std::string variable = "";
std::string variable = std::string();
Background:
I basically got the idea here (the second code sample for the accepted answer) when I was trying to empty out a stringstream.
I also had to start using it when I began learning classes and realized that member variable initializations had to be done in the constructor, not just following its definition in the header. For example, initializing a vector:
// Header.h
class myClass
{
private:
std::vector<std::string> myVector;
};
// Source.cpp
myClass::myClass()
{
for (int i=0;i<5;i++)
{
myVector.push_back(std::string());
}
}
Any clarity on this will be greatly appreciated!
Edit
After reading again, I realized that you explicitely asked about the default constructor while I provided a lot of examples with a 1 parameter constructor.
For Visual Studio C++ compiler, the following code only executes the default constructor, but if the copy constructor is defined explicit, it still complains because the never called copy constructor can't be called this way.
#include <iostream>
class MyInt {
public:
MyInt() : _i(0) {
std::cout << "default" << std::endl;
}
MyInt(const MyInt& other) : _i(other._i) {
std::cout << "copy" << std::endl;
}
int _i;
};
int main() {
MyInt i = MyInt();
return i._i;
}
Original (typo fixed)
For int variables, there is no difference between the forms.
Custom classes with a 1 argument constructor also accept assignment initialization, unless the constructor is marked as explicit, then the constructor call Type varname(argument) is required and assignment produces a compiler error.
See below examples for the different variants
class MyInt1 {
public:
MyInt1(int i) : _i(i) { }
int _i;
};
class MyInt2 {
public:
explicit MyInt2(int i) : _i(i) { }
int _i;
};
class MyInt3 {
public:
explicit MyInt3(int i) : _i(i) { }
explicit MyInt3(const MyInt3& other) : _i(other._i) { }
int _i;
};
int main() {
MyInt1 i1_1(0); // int constructor called
MyInt1 i1_2 = 0; // int constructor called
MyInt2 i2_1(0); // int constructor called
MyInt2 i2_2 = 0; // int constructor explicit - ERROR!
MyInt2 i2_3 = MyInt2(0); // int constructor called
MyInt3 i3_1(0); // int constructor called
MyInt3 i3_2 = 0; // int constructor explicit - ERROR!
MyInt3 i3_3 = MyInt3(0); // int constructor called, copy constructor explicit - ERROR!
}
The main difference between something like:
int i = int(); and int i = 0;
is that using a default constructor such as int() or string(), etc., unless overloaded/overridden, will set the variable equal to NULL, while just about all other forms of instantiation and declarations of variables will require some form of value assignment and therefore will not be NULL but a specific value.
As far as my knowledge on efficiency, neither one is "better".

access to private constructor by friend class

Problem: source code (see. below) is compiled MSVC , but does not compile g++.
#include <iostream>
using namespace std;
class B;
class A
{
friend class B;
private:
int i;
A(int n) : i(n) { }
public :
A(A& a) { if (&a != this) *this = a; }
int display() { return i;}
};
class B
{
public :
B() { }
A func( int j) { return A(j); }
};
int main(int argc, char **argv)
{
B b;
A a(b.func((10)));
cout << " a.i = " << a.display() << endl;
return 0;
}
Output:
GNU g++ compilation message:
g++ -c main.cpp
main.cpp: In member function 'A B::func(int)':
main.cpp:25:38: error: no matching function for call to 'A::A(A)'
A func( int j) { return A(j); }
^
main.cpp:25:38: note: candidates are:
main.cpp:17:9: note: A::A(A&)
A(A& a) { if (&a != this) \*this = a; }
^
main.cpp:17:9: note: no known conversion for argument 1 from 'A' to 'A&'
main.cpp:14:9: note: A::A(int)
A(int n) : i(n) { }
^
main.cpp:14:9: note: no known conversion for argument 1 from 'A' to 'int'
main.cpp: In function 'int main(int, char\**)':
...
Why? Class B is a friend for class A then B has access to private constructor A(int i).
Your copy constructor must take a const reference so it can bind to a temporary A:
A(const A& a) { .... }
The C++ standard does not allow binding a non-const reference to a temporary. g++ is strict about this, while MSVC has an "extension" that breaks the rule.
Besides that, your implementation of the copy constructor looks strange. You should not be using the assignment operator there. For a class like A, you should use the implicitly generated copy constructor, in other words, remove your own:
class A
{
friend class B;
private:
int i;
A(int n) : i(n) { }
public :
int display() const { return i;}
};
It is a bug of MS VC++. It shall not compile the code. The problem is that the error message of g++ is not cllear enough.
In fact the compiler tries to elide using of a copy constructor and to build the object directly in 'a' using constructor A(int n);. But that it will be possible an appropriate copy constructor shall be available. As a temporary object should be copied (if the ilision would not be used) then the copy constructor shall have const reference to object. That is instead of A(A& a); your copy constructor shall be declared as A( const A& a); If you will make the changes then g++ will compile the code.
The most simple way to define copy constructor for your example is to write
A( const A & ) = default;
However I am not sure whether your MS VC++ compiler supports this feature.

Temporaries created during assignment operation

if every assignment creates a temporary to copy the object into lvalue, how can you check to see in VC++ 8.0?
class E
{
int i, j;
public:
E():i(0), j(0){}
E(int I, int J):i(I), j(J){}
};
int main()
{
E a;
E b(1, 2);
a = b //would there be created two copies of b?
}
Edit:
Case 2:
class A
{
int i, j;
public:
A():i(0), j(0){}
};
class E
{
int i, j;
A a;
public:
E():i(0), j(0){}
E(int I, int J):i(I), j(J){}
E(const E &temp)
{
a = temp; //temporary copy made?
}
};
int main()
{
E a;
E b(1, 2);
a = b //would there be created two copies of b?
}
From your comment, you made it clear that you didn't quite understand this C++-FAQ item.
First of all, there are no temporaries in the code you presented. The compiler declared A::operator= is called, and you simply end up with 1 in a.i and 2 in a.j.
Now, regarding the link you provided, it has to do with constructors only. In the following code :
class A
{
public:
A()
{
s = "foo";
}
private:
std::string s;
};
The data member s is constructed using std::string parameterless constructor, then is assigned the value "foo" in A constructor body. It's preferable (and as a matter of fact necessary in some cases) to initialize data members in an initialization list, just like you did with i and j :
A() : s("foo")
{
}
Here, the s data member is initialized in one step : by calling the appropriate constructor.
There are a few standard methods that are created automatically for you if you don't provide them. If you write
struct Foo
{
int i, j;
Foo(int i, int j) : i(i), j(j) {}
};
the compiler completes that to
struct Foo
{
int i, j;
Foo(int i, int j) : i(i), j(j)
{
}
Foo(const Foo& other) : i(other.i), j(other.j)
{
}
Foo& operator=(const Foo& other)
{
i = other.i; j = other.j;
return *this;
}
};
In other words you will normally get a copy constructor and an assignment operator that work on an member-by-member basis. In the specific the assignment operator doesn't build any temporary object.
It's very important to understand how those implicitly defined method works because most of the time they're exact the right thing you need, but sometimes they're completely wrong (for example if your members are pointers often a member-by-member copy or assignment is not the correct way to handle the operation).
This would create a temporary:
E makeE( int i, int j )
{
return E(i, j);
}
int main()
{
E a;
a = makeE( 1, 2 );
E b = makeE( 3, 4 );
}
makeE returns a temporary. a is assigned to the temporary and the assignment operator is always called here. b is not "assigned to", as it is being initialised here, and requires an accessible copy-constructor for that to work although it is not guaranteed that the copy-constructor will actually be called as the compiler might optimise it away.