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.
Related
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
I have a class that contains POD members. I need to have all members copied, except one (member a in the example case). The way I'm doing it right now is as follows:
class Example
{
private:
int a = 0;
int b = 0;
int c = 0;
int d = 0;
double e = 0;
public:
Example& operator=(const Example &rhs)
{
b = rhs.b;
c = rhs.c;
d = rhs.d;
e = rhs.e;
return *this;
}
Example() {};
Example(const Example& toCopy)
{
*this = toCopy;
}
};
Is there a way to mark the variable to not copy, as doing it this way is verbose and prone to bugs if I later modify this class?
You can wrap the "odd man out", a, in a struct and define that structs behavior separately:
class Example
{
private:
CopyLess a;
int b = 0;
int c = 0;
int d = 0;
double e = 0;
struct CopyLess {
int a = 0;
CopyLess& operator=(const CopyLess&) { return *this; }
CopyLess(const CopyLess&) {}
};
};
Note that I didn't bother writing any special members for Example anymore because the defaults do what you want. Writing code this way to avoid writing special members as much as possible is called the "Rule of Zero", more information and examples: http://www.nirfriedman.com/2015/06/27/cpp-rule-of-zero/.
No, you cannot make the implicit copy assignment skip members. Defining a custom assignment operator as you have done is the way to achieve your desired behaviour.
Doing it this way is verbose and prone to bugs if I later modify this class
You can group the copied members into a single subobject. That way the custom copy assignment is not fragile to changes and verbosity remains constant in relation to number of copied members.
Bonus: You don't need to specify value initialization for the members separately, but one for the entire subobject is enough.
class Example
{
int a = 0;
struct {
int b;
int c;
int d;
double e;
} state = {};
public:
Example& operator=(const Example &rhs)
{
state = rhs.state;
return *this;
}
...
Since the members are private this won't change the existing API of the class.
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".
Suppose I have a class A, whose constructor requires an argument x.
class A
{
public:
int a;
A(int x) { a = x; std::cout << a << std::endl; }
~A() {}
};
Now I want to allocate an array of A, and wrap it in another class B (in reality it should be a 2-dimensional array of A, mapped onto a 1-dimensional array, which is why I need to wrap it). Since constructor of A requires argument, I cannot use new[] (…right?), so I have to have an A**. Also I don’t want B to know about x, so my B is like this:
class B
{
private:
A** As;
const int n;
public:
B(int nn): n(nn) { As = new A*[n]; }
~B() { delete[] As; }
A* at(int i) { return As[i]; }
const A* at(int i) const { return As[i]; }
};
Note that “subscription operator” loosely means that at() function. Now my main function is like this:
int main()
{
B b(3);
int x = -1;
for(int i = 0; i < 3; i++)
{
b.at(i) = new A(x);
}
return 0;
}
When I compile this with g++, it prints an error “lvalue required as left operand of assignment” at my “new” line. Then I change my signature of at() to
A*& at(int i)
and it works.
What’s bothering my is that A*&, which just looks weird to me…
Is this A*& something I should use? Or any other way to deal with an array of objects, whose constructor requires arguments? BTW we don’t have c++11 and boost available on our target machine…
"Or any other way to deal with an array of objects, whose constructor requires arguments?"
Use std::vector, you don't need C++11 for it, neither any additional libraries:
#include <vector>
...
std::vector<A> myObjects(n, A(0)); // objects will be constructed by calling A(0)
Your class B could look the following way:
class B
{
private:
std::vector<A> As;
const int n;
public:
B(int n): n(n), As(std::vector<A>(n, A(0))) { }
// no explicit destructor needed
// memory management is handled by std::vector object automatically
A& at(int i) { return As[i]; }
const A& at(int i) const { return As[i]; }
};
Note that vector's elements are stored within continuous block of memory and lifetime of these elements is tied to the lifetime of instance of B. Once the B is destructed, so is the vector and so are the elements that were stored in it. If n is a constant known at compile time, you might also consider using std::array instead.
The & operator has a role to change an function parameter or a return variable to a reference.
Without & the value of the variable will be copied into a temporal variable, therefore the original variable will not be sensible to any value changes.
By referenced handling the parameter will be the original variable only the name differs, but signs the same memory block.
In this example the b.at(i) statement will be copied into a temporary constant variable, which is unusable in the left side of = statement.
But by referenced return of this statement it points to the original As[i] memory block, only the 'name' differs, and so can be changed its value too.
Sorry for the basic question, but I'm having trouble finding the right thing to google.
#include <iostream>
#include <string>
using namespace std;
class C {
public:
C(int n) {
x = new int(n);
}
~C( ) {
delete x;
}
int getX() {return *x;}
private:
int* x;
};
void main( ) {
C obj1 = C(3);
obj1 = C(4);
cout << obj1.getX() << endl;
}
It looks like it does the assignment correctly, then calls the destructor on obj1 leaving x with a garbage value rather than a value of 4. If this is valid, why does it do this?
If there is a class C that has a constructor that takes an int, is this code valid?
C obj1(3);
obj1=C(4);
Assuming C has an operator=(C) (which it will by default), the code is valid. What will happen is that in the first line obj1 is constructed with 3 as a the parameter to the constructor. Then on the second line, a temporary C object is constructed with 4 as a parameter and then operator= is invoked on obj1 with that temporary object as a parameter. After that the temporary object will be destructed.
If obj1 is in an invalid state after the assignment (but not before), there likely is a problem with C's operator=.
Update: If x really needs to be a pointer you have three options:
Let the user instead of the destructor decide when the value of x should be deleted by defining a destruction method that the user needs to call explicitly. This will cause memory leaks if the user forgets to do so.
Define operator= so that it will create a copy of the integer instead of a copy of the value. If in your real code you use a pointer to something that's much bigger than an int, this might be too expensive.
Use reference counting to keep track how many instances of C hold a pointer to the same object and delete the object when its count reaches 0.
If C contains a pointer to something, you pretty much always need to implement operator=. In your case it would have this signature
class C
{
public:
void operator=(const C& rhs)
{
// For each member in rhs, copy it to ourselves
}
// Your other member variables and methods go here...
};
I do not know enough deep, subtle C++ to explain the problem you are encountering. I do know, however, that it's a lot easier to make sure a class behaves the way you expect if you follow the Rule of Three, which the code you posted violates. Basically, it states that if you define any of the following you should define all three:
Destructor
Copy constructor
Assignment operator
Note as well that the assignment operator implementation needs to correctly handle the case where an object is assigned to itself (so-called "self assignment"). The following should work correctly (untested):
#include <iostream>
#include <string>
using namespace std;
class C {
public:
C(int n) {
x = new int(n);
}
C(const C &other): C(other.getX()) { }
~C( ) {
delete x;
}
void operator=(const C &other) {
// Just assign over x. You could reallocate if you first test
// that x != other.x (the pointers, not contents). The test is
// needed to make sure the code is self-assignment-safe.
*x = *(other.x);
}
int getX() {return *x;}
private:
int* x;
};
void main( ) {
C obj1 = C(3);
obj1 = C(4);
cout << obj1.getX() << endl;
}
Basically you are trying to re-implement a smart pointer.
This is not trivial to get correct for all situations.
Please look at the available smart pointers in the standard first.
A basic implementation (Which will fail under certain situations (copy one of the standard ones to get a better one)). But this should cover the basics:
class X
{
int* data;
public:
// Destructor obvious
~X()
{
delete data;
}
// Easy constructor.
X(int x)
:data(new int(x))
{}
// Copy constructor.
// Relatively obvious just do the same as the normal construcor.
// Get the value from the rhs (copy). Note A class is a friend of
// itself and thus you can access the private members of copy without
// having to use any accessor functions like getX()
X(X const& copy)
:data(new int(copy.x))
{}
// Assignment operator
// This is an example of the copy and swap idiom. This is probably overkill
// for this trivial example but provided here to show how it is used.
X& operator=(X const& copy)
{
X tmp(copy);
this->swap(tmp);
return this;
}
// Write a swap() operator.
// Mark it is as no-throw.
void swap(X& rhs) throws()
{
std::swap(data,rhs.data);
}
};
NEW:
What's happening is that your destructor has deallocated the memory allocated by the constructor of C(4). So the pointer you have copied over from C(4) is a dangling pointer i.e. it still points to the memory location of the deallocated memory
class C {
public:
C(int n) {
x = new int(n);
}
~C( ) {
//delete x; //Don't deallocate
}
void DeallocateX()
{
delete x;
}
int getX() {return *x;}
private:
int* x;
};
int main(int argc, char* argv[])
{
// Init with C(3)
C obj1 = C(3);
// Deallocate C(3)
obj1.DeallocateX();
// Allocate memory and store 4 with C(4) and pass the pointer over to obj1
obj1 = C(4);
// Use the value
cout << obj1.getX() << endl;
// Cleanup
obj1.DeallocateX();
return 0;
}
Be explicit about ownership of pointers! auto_ptr is great for this. Also, when creating a local don't do C obj1 = C(3) that creates two instances of C and initializes the first with the copy constructor of the second.
Heed The Guru.
class C {
public:
C(int n) : x(new int(n)) { }
int getX(){ return *x; }
C(const C& other) : x(new int(*other.x)){}
C& operator=(const C& other) { *x = *other.x; return *this; }
private:
std::auto_ptr<int> x;
};
int main() {
C obj1(3);
obj1 = C(4);
std::cout << obj1.getX() << std::endl;
}
When are you testing the value of obj1? Is it after you leave the scope?
In your example, obj1 is a stack object. That means as soon as you leave the function in which it defined, it gets cleaned up (the destructor is called). Try allocating the object on the heap:
C *obj1 = new C(3);
delete obj1;
obj1 = new C(4);