Assignment operator when there are static, const members? - c++

I have to write one new class with members something like
class A
{
static int i;
const int j;
char * str;
...
...
};
Now I want to write assignment operator for it.
A& A::operator=(const A& rhs)
{
if(this != rhs)
{
delete [] str;
str = new char[strlen(rhs.str)+1];
strcpy(str, rhs.str);
}
return * this;
}
Is it right? I shall ignore the static and const members(?).

The assignment operator copies one object into another. Since all objects of the same type share the same static members, there's no reason to copy the static members.
const members are another matter. You can't (well, shouldn't) change them, but if two objects have different values for a const member, it might not be a good idea to copy one object into another; the const member won't have the right value. That's why the compiler doesn't generate a copy assignment operator for classes that have const members. So you first have to be sure that copying such an object makes sense, even with the wrong value for the const members; and then ask yourself why it has const members if they don't affect how it behaves.
References too. (yes, there's an echo in here)

Static members don't belong to a single object, so you don't need to copy those.
const members can't be changed, so you really can't do a proper copy. References too.

Related

C++ compiler 'shallow' copies and assignments

I'm taking a class on object oriented programming using C++.
In our text it says,
If we do not declare a copy constructor, the compiler inserts code
that implements a shallow copy. If we do not declare an assignment
operator, the compiler inserts code that implements a shallow
assignment.
What I want to know, is whether this is in fact true, what the alluded to compiler mechanism is actually called, and how it works.
This is not a question about copy constructors, it is about compiler behavior.
EDIT> More context
Copy Constructor as defined by the text:
The definition of a copy constructor contains logic that
performs a shallow copy on all of the non-resource instance variables
allocates memory for each new resource
copies data from the source resource(s) to the newly created resource(s)
Resource as defined by the text
Memory that an object allocates at run-time represents a resource of that
object's class.
The management of this resource requires additional logic that was unnecessary for simpler classes that do not access resources. This additional logic
ensures proper handling of the resource and is often called deep copying and
assignment.
It's more accurate to say that the compiler defines a default copy constructor and a default copy assignment operator. These will copy/construct the new object by simply calling the copy constructor for all of the member variables.
For primitives like ints and floats, this usually isn't a problem.
For pointers, though. This is bad news! What happens when the first object deletes that pointer? Now the other object's pointer is invalid!
If a member variable cannot be copied (perhaps you used a std::unique_ptr to fix the above problem), then the default copy assignment/ctor won't work. How can you copy something that can't be copied? This will lead to a compiler error.
If you define your own copy constructor/assignment operator, you can make a "deep copy" instead. You can:
Create a new object, rather than copying the pointer
Explicitly "shallow copy" a pointer
Mix the above two based on what you actually want!
Initialize member variables with default/custom values in copied objects rather than copy whatever was in the original object.
Disable copying altogether
On and on and on
As you can see, there are plenty of reasons why you'd want to implement (or explicitly prohibit) your own copy assignment operator, copy constructor, their move counterparts, and destructor. In fact, there's a well-known C++ idiom known as The Rule of Five (formerly the Rule of 3) that can guide your decision on when to do this.
Yes it's true, and it's indeed called shallow copying. As for how it works, lets say you have a pointer variable, and you assign it to another pointer variable. This only copies the pointer and not what it points to, this is a shallow copy. A deep copy would have created a new pointer, and copied the actual contents that the first pointer points to.
Something like this:
int* a = new int[10];
// Shallow copying
int* b = a; // Only copies the pointer a, not what it points to
// Deep copying
int* c = new int[10];
std::copy(a, a + 10, c); // Copies the contents pointed to by a
The problem with shallow copying in regards to pointers should be quite obvious: After the initialization of b in the above example, you have two pointers both pointing to the same memory. If one then does delete[] a; then both pointers become invalid. If the two pointers are in different objects of some class, then there is no real connection between the pointers, and the second object won't know if the first object have deleted its memory.
The code for shallow copy is a simple assignment for every field. If:
class S {
T f;
};
S s1, s2;
A assignment like s1=s2; is equivalent to what happens in the following:
class S {
T f;
public:
S &operator=(const S&s) {
this->f = s.f; // and such for every field, whatever T is
}
};
S s1, s2;
s1=s2;
This is stated in 12.8-8 of the draft standard:
The implicitly-declared copy constructor for a class X will have the
form X::X(const X&) if
— each direct or virtual base class B of X has
a copy constructor whose first parameter is of type const B& or const
volatile B&, and
— for all the non-static data members of X that are
of a class type M (or array thereof), each such class type has a copy
constructor whose first parameter is of type const M& or const
volatile M&.123
Otherwise, the implicitly-declared copy constructor
will have the form X::X(X&)
12.8-28 says:
The implicitly-defined copy/move assignment operator for a non-union
class X performs memberwise copy/move assignment of its subobjects. [...] in the order in which they were declared in the class definition.
I'll use a basic class to define the behavior of the compiler as best as I know how to.
class Student sealed {
private:
std::string m_strFirstName;
std::string m_strLastName;
std::vector<unsigned short> m_vClassNumbers;
std::vector<std::string> m_vTeachers;
std::vector<unsigned short> m_vClassGrades;
public:
Student( const std::string& strFirstName, const std::string& strLastName );
std::string getFirstName() const;
std::string getLastName() const;
void setClassRoster( std::vector<unsigned short>& vClassNumbers );
std::vector<unsigned short>& getClassRoster() const;
void setClassTeachers( std::vector<std::string>& vTeachers );
std::vector<std::string>& getClassTeachers() const;
void setClassGrades( std::vector<unsigned short>& vGrades );
std::vector<unsigned short>& getGrades() const;
// Notice That These Are Both Commented Out So The Compiler Will
// Define These By Default. And These Will Make Shallow / Stack Copy
// Student( const Student& c ); // Default Defined
// Student& operator=( const Student& c ); // Default Defined
};
The version of this class with its declaration by default will construct both a copy constructor and an equal operator.
class Student sealed {
private:
std::string m_strFirstName;
std::string m_strLastName;
std::vector<unsigned short> m_vClassNumbers;
std::vector<std::string> m_vTeachers;
std::vector<unsigned short> m_vClassGrades;
public:
Student( const std::string& strFirstName, const std::string& strLastName );
std::string getFirstName() const;
std::string getLastName() const;
void setClassRoster( std::vector<unsigned short>& vClassNumbers );
std::vector<unsigned short>& getClassRoster() const;
void setClassTeachers( std::vector<std::string>& vTeachers );
std::vector<std::string>& getClassTeachers() const;
void setClassGrades( std::vector<unsigned short>& vGrades );
std::vector<unsigned short>& getGrades() const;
private:
// These Are Not Commented Out But Are Defined In The Private Section
// These Are Not Accessible So The Compiler Will No Define Them
Student( const Student& c ); // Not Implemented
Student& operator=( const Student& c ); // Not Implemented
};
Where the second version of this class will not since I declared both of them as being private!
This is probably the best way I can demonstrate this. I only showed the header file interface to this class since the c++ source or code to be compiled is not of a concern. The difference in how these two are defined during the Pre-Compile Stage dictates how the Compiler Will Work before it begins to compile the source code into object code.
Keep in mind though that the standard library strings & containers do implement their own Copy Constructor & Assignment Operators! But the same concept applies to the behavior of the compiler if a class has basic types such as int, float, double, etc. So the compiler will treat a Simple class in the same manner according to its declaration.
class Foo {
private:
int m_idx;
float m_fValue;
public:
explicit Foo( float fValue );
// Foo( const Foo& c ); // Default Copy Constructor
// Foo& operator=( const Foo& c ); // Default Assignment Operator
};
Second Version
class Foo {
private:
int m_idx;
float m_fValue;
public:
explicit Foo( float fValue );
private:
Foo( const Foo& c ); // Not Implemented
Foo& operator=( const Foo& c ); // Not Implemented
};
The compiler will treat this class in the same manner; it will not define either of these since they will not be implemented due to being declared as private.

Add one object to another set of objects in C++

I'm working on my assignment in C++ course.
I have to create operator+= which will add an object to another set of object.
So, how do I implement operator+= here?
class classNew
{
anotherClass *my_objects;
public:
// TODO: classNew(int, char const *)
classNew operator+=(const anotherClass & rhs);
};
int main()
{
classNew d1(7, "w");
anotherClass sgs[5];
// somehow init sgs[0]..[4]?
for (int i=0; i<sizeof(sgs)/sizeof(*sgs); ++i)
d1 += sgs[i];
}
UPDATE:
I have something like this
newClass newClass::operator+=(const anotherClass& seg){
this->my_objs[n_seg] = seg;
return *this;
}
Unless your operator+= is intended to modify the object you're adding, which would be highly unusual, I'd suggest one two simple changes to the signature:
classNew & classNew::operator+=(const anotherClass& rhs);
You always want to return a reference to the class, otherwise you get a copy.
You have a pointer to anotherClass in your class, I assume that this is actually a pointer to an array. You simply have to copy the passed rhs to the appropriate spot in your array, reallocating it and growing it if necessary. If my assumption is incorrect, you just need to do whatever addition is defined as for your class.
If this weren't an assignment I would also suggest replacing the pointer with a std::vector<anotherClass>.

Making shallow copy inside assignment operator

I need to implement an assignment operator for a class with a lot of members which I don't want to assign manually. Can I first make a shallow memory copy and then perform the necessary initializations?
class C
{
public:
C &operator=(const C &rhs)
{
if (&rhs == this)
return *this;
memcpy(this, &rhs, sizeof(C));
Init(rhs);
return *this;
}
.........
};
Thanks.
No. Unless the object has a POD type, this is undefined behavior. And
a user defined assignment operator means that it's not a POD. And in
practice, it could fail for a number of reasons.
One possible solution is to define a nested POD type with the data
members, and simply assign it, e.g.:
class C
{
struct Data { /* ... */ };
Data myData;
public:
C& operator=( C const& other )
{
myData = other.myData;
return *this;
}
};
Of course, that means that you need to constantly refer to each member
as myData.x, rather than simply x.
Well you could, but all your copied pointer members(if any) will then point to the same object and if that object goes out of scope, You would be left with a dangling pointer for all other objects which refer to it.
You are trying to dereference a C++ reference using the * operator. Unless you have operator* defined for this class it's not gonna work.
I mean in line
memcpy(this, *rhs, sizeof(C));

C++ overloading assignment operator

I have a class called Location and I needed to add a CArray to its member variables. This change caused the need to overload the assignment operator.
Is there a way to copy all of the variables in this class type that were being copied before I made the change and just add the additional code to copy the CArray without copying every single member variable individually?
Location& Location::operator=(const Location &rhs)
{
// Only do assignment if RHS is a different object from this.
if (this != &rhs)
{
//Copy CArray
m_LocationsToSkip.Copy(rhs.m_LocationsToSkip);
//Copy rest of member variables
//I'd prefer not to do the following
var1 = rhs.var1;
var2 = rhs.var2;
//etc
}
return *this;
}
Yes, sort of. Use a type that overloads operator= itself, so you don't have to do it in the containing class instead. Even when writing MFC code, I still mostly use std::vector, std::string, etc., instead of the MFC collection and string classes. Sometimes you're pretty much stuck using CString, but I can't recall the last time I used CArray instead of std::vector.
Yes. What I usually do is to put everything in a Members struct in the class except what is not copyable. Like this:
class Location
{
struct Members
{
int var1, var2;
};
Members m;
CArray m_LocationsToSkip;
public:
Location& operator=(Location const& rhs);
};
Location& Location::operator=(const Location &rhs)
{
// Only do assignment if RHS is a different object from this.
if (this != &rhs)
{
//Copy CArray
m_LocationsToSkip.Copy(rhs.m_LocationsToSkip);
//Copy rest of member variables
m = rhs.m; //will use Members automatically generated operator=
//which should do the correct thing because you only put
//normally copyable members in m
}
return *this;
}
I first posted about this here: https://stackoverflow.com/questions/469696/what-is-your-most-useful-c-c-utility/1609496#1609496
No you cant.
Best way to do this is use script to generate real code.
This is usually done with what's called "copy and swap idiom". You implement a copy constructor and a swap() method that exchanges member values and, most importantly, pointers to external data. With that your assignment operator looks like:
C& C::operator=( const C& c ) {
C tmp( c );
this->swap( tmp );
return *this;
}
You don't even need a self-assignment guard with this.

C++: STL troubles with const class members

It is an open ended question.
Effective C++. Item 3. Use const whenever possible. Really?
I would like to make anything which doesn't change during the objects lifetime const. But const comes with it own troubles. If a class has any const member, the compiler generated assignment operator is disabled. Without an assignment operator a class won't work with STL. If you want to provide your own assignment operator, const_cast is required. That means more hustle and more room for error. How often you use const class members?
EDIT: As a rule, I strive for const correctness because I do a lot of multithreading. I rarely need to implemented copy control for my classes and never code delete (unless it is absolutely necessary). I feel that the current state of affairs with const contradicts my coding style. Const forces me to implement assignment operator even though I don't need one. Even without const_cast assignment is a hassle. You need to make sure that all const members compare equal and then manually copy all non-const member.
Code. Hope it will clarify what I mean. The class you see below won't work with STL. You need to implement an assignment for it, even though you don't need one.
class Multiply {
public:
Multiply(double coef) : coef_(coef) {}
double operator()(double x) const {
return coef_*x;
}
private:
const double coef_;
};
You said yourself that you make const "anything which doesn't change during the objects lifetime". Yet you complain about the implicitly declared assignment operator getting disabled. But implicitly declared assignment operator does change the contents of the member in question! It is perfectly logical (according to your own logic) that it is getting disabled. Either that, or you shouldn't be declaring that member const.
Also, providing you own assignment operator does not require a const_cast. Why? Are you trying to assign to the member you declared const inside your assignment operator? If so, why did you declare it const then?
In other words, provide a more meaningful description of the problems you are running into. The one you provided so far is self-contradictory in the most obvious manner.
As AndreyT pointed out, under these circumstances assignment (mostly) doesn't make a lot of sense. The problem is that vector (for one example) is kind of an exception to that rule.
Logically, you copy an object into the vector, and sometime later you get back another copy of the original object. From a purely logical viewpoint, there's no assignment involved. The problem is that vector requires that the object be assignable anyway (actually, all C++ containers do). It's basically making an implementation detail (that somewhere in its code, it might assign the objects instead of copying them) part of the interface.
There is no simple cure for this. Even defining your own assignment operator and using const_cast doesn't really fix the problem. It's perfectly safe to use const_cast when you get a const pointer or reference to an object that you know isn't actually defined to be const. In this case, however, the variable itself is defined to be const -- attempting to cast away the constness and assign to it gives undefined behavior. In reality, it'll almost always work anyway (as long as it's not static const with an initializer that's known at compile time), but there's no guarantee of it.
C++ 11 and newer add a few new twists to this situation. In particular, objects no longer need to be assignable to be stored in a vector (or other collections). It's sufficient that they be movable. That doesn't help in this particular case (it's no easier to move a const object than it is to assign it) but does make life substantially easier in some other cases (i.e., there are certainly types that are movable but not assignable/copyable).
In this case, you could use a move rather than a copy by adding a level of indirection. If your create an "outer" and an "inner" object, with the const member in the inner object, and the outer object just containing a pointer to the inner:
struct outer {
struct inner {
const double coeff;
};
inner *i;
};
...then when we create an instance of outer, we define an inner object to hold the const data. When we need to do an assignment, we do a typical move assignment: copy the pointer from the old object to the new one, and (probably) set the pointer in the old object to a nullptr, so when it's destroyed, it won't try to destroy the inner object.
If you wanted to badly enough, you could use (sort of) the same technique in older versions of C++. You'd still use the outer/inner classes, but each assignment would allocate a whole new inner object, or you'd use something like a shared_ptr to let the outer instances share access to a single inner object, and clean it up when the last outer object is destroyed.
It doesn't make any real difference, but at least for the assignment used in managing a vector, you'd only have two references to an inner while the vector was resizing itself (resizing is why a vector requires assignable to start with).
I very rarely use them - the hassle is too great. Of course I always strive for const correctness when it comes to member functions, parameters or return types.
Errors at compile time are painful, but errors at runtime are deadly. Constructions using const might be a hassle to code, but it might help you find bugs before you implement them. I use consts whenever possible.
I try my best to follow the advice of using const whenever possible, however I agree that when it comes to class members, const is a big hassle.
I have found that I am very careful with const-correctness when it comes to parameters, but not as much with class members. Indeed, when I make class members const and it results in an error (due to using STL containers), the first thing I do is remove the const.
I'm wondering about your case... Everything below is but supposition because you did not provide the example code describing your problem, so...
The cause
I guess you have something like:
struct MyValue
{
int i ;
const int k ;
} ;
IIRC, the default assignment operator will do a member-by-member assignment, which is akin to :
MyValue & operator = (const MyValue & rhs)
{
this->i = rhs.i ;
this->k = rhs.k ; // THIS WON'T WORK BECAUSE K IS CONST
return *this ;
} ;
Thus, this won't get generated.
So, your problem is that without this assignment operator, the STL containers won't accept your object.
As far I as see it:
The compiler is right to not generate this operator =
You should provide your own, because only you know exactly what you want
You solution
I'm afraid to understand what do you mean by const_cast.
My own solution to your problem would be to write the following user defined operator :
MyValue & operator = (const MyValue & rhs)
{
this->i = rhs.i ;
// DON'T COPY K. K IS CONST, SO IT SHOULD NO BE MODIFIED.
return *this ;
} ;
This way, if you'll have:
MyValue a = { 1, 2 }, b = {10, 20} ;
a = b ; // a is now { 10, 2 }
As far as I see it, it is coherent. But I guess, reading the const_cast solution, that you want to have something more like:
MyValue a = { 1, 2 }, b = {10, 20} ;
a = b ; // a is now { 10, 20 } : K WAS COPIED
Which means the following code for operator =:
MyValue & operator = (const MyValue & rhs)
{
this->i = rhs.i ;
const_cast<int &>(this->k) = rhs.k ;
return *this ;
} ;
But, then, you wrote in your question:
I would like to make anything which doesn't change during the objects lifetime const
With what I supposed is your own const_cast solution, k changed during the object lifetime, which means that you contradict yourself because you need a member variable that doesn't change during the object lifetime unless you want it to change!
The solution
Accept the fact your member variable will change during the lifetime of its owner object, and remove the const.
you can store shared_ptr to your const objects in STL containers if you'd like to retain const members.
#include <iostream>
#include <boost/foreach.hpp>
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
#include <vector>
class Fruit : boost::noncopyable
{
public:
Fruit(
const std::string& name
) :
_name( name )
{
}
void eat() const { std::cout << "eating " << _name << std::endl; }
private:
const std::string _name;
};
int
main()
{
typedef boost::shared_ptr<const Fruit> FruitPtr;
typedef std::vector<FruitPtr> FruitVector;
FruitVector fruits;
fruits.push_back( boost::make_shared<Fruit>("apple") );
fruits.push_back( boost::make_shared<Fruit>("banana") );
fruits.push_back( boost::make_shared<Fruit>("orange") );
fruits.push_back( boost::make_shared<Fruit>("pear") );
BOOST_FOREACH( const FruitPtr& fruit, fruits ) {
fruit->eat();
}
return 0;
}
though, as others have pointed out it's somewhat of a hassle and often easier in my opinion to remove the const qualified members if you desire the compiler generated copy constructor.
I only use const on reference or pointer class members. I use it to indicate that the target of the reference or pointer should not be changed. Using it on other kinds of class members is a big hassle as you found out.
The best places to use const is in function parameters, pointers and references of all kinds, constant integers and temporary convenience values.
An example of a temporary convenience variable would be:
char buf[256];
char * const buf_end = buf + sizeof(buf);
fill_buf(buf, buf_end);
const size_t len = strlen(buf);
That buf_end pointer should never point anywhere else so making it const is a good idea. The same idea with len. If the string inside buf never changes in the rest of the function then its len should not change either. If I could, I would even change buf to const after calling fill_buf, but C/C++ does not let you do that.
The point is that the poster wants const protection within his implementation but still wants the object assignable. The language does not support such semantics conveniently as constness of the member resides at the same logical level and is tightly coupled with assignability.
However, the pImpl idiom with a reference counted implementation or smart pointer will do exactly what the poster wants as assignability is then moved out of the implementation and up a level to the higher level object. The implementation object is only constructed/destructed whence assignment is never needed at the lower level.
I think your statement
If a class has const any member, the
compiler generated assignment operator
is disabled.
Might be incorrect. I have classes that have const method
bool is_error(void) const;
....
virtual std::string info(void) const;
....
that are also used with STLs. So perhaps your observation is compiler dependent or only applicable to the member variables?
I would only use const member iff the class itself is non-copyable. I have many classes that I declare with boost::noncopyable
class Foo : public boost::noncopyable {
const int x;
const int y;
}
However if you want to be very sneaky and cause yourself lots of potential
problems you can effect a copy construct without an assignment but you have to
be a bit careful.
#include <new>
#include <iostream>
struct Foo {
Foo(int x):x(x){}
const int x;
friend std::ostream & operator << (std::ostream & os, Foo const & f ){
os << f.x;
return os;
}
};
int main(int, char * a[]){
Foo foo(1);
Foo bar(2);
std::cout << foo << std::endl;
std::cout << bar<< std::endl;
new(&bar)Foo(foo);
std::cout << foo << std::endl;
std::cout << bar << std::endl;
}
outputs
1
2
1
1
foo has been copied to bar using the placement new operator.
It isn't too hard. You shouldn't have any trouble making your own assignment operator. The const bits don't need to be assigned (as they're const).
Update
There is some misunderstanding about what const means. It means that it will not change, ever.
If an assignment is supposed to change it, then it isn't const.
If you just want to prevent others changing it, make it private and don't provide an update method.
End Update
class CTheta
{
public:
CTheta(int nVal)
: m_nVal(nVal), m_pi(3.142)
{
}
double GetPi() const { return m_pi; }
int GetVal() const { return m_nVal; }
CTheta &operator =(const CTheta &x)
{
if (this != &x)
{
m_nVal = x.GetVal();
}
return *this;
}
private:
int m_nVal;
const double m_pi;
};
bool operator < (const CTheta &lhs, const CTheta &rhs)
{
return lhs.GetVal() < rhs.GetVal();
}
int main()
{
std::vector<CTheta> v;
const size_t nMax(12);
for (size_t i=0; i<nMax; i++)
{
v.push_back(CTheta(::rand()));
}
std::sort(v.begin(), v.end());
std::vector<CTheta>::const_iterator itr;
for (itr=v.begin(); itr!=v.end(); ++itr)
{
std::cout << itr->GetVal() << " " << itr->GetPi() << std::endl;
}
return 0;
}
Philosophically speaking, it looks as safety-performance tradeoff. Const used for safety. As I understand, containers use assignment to reuse memory, i.e. for sake of performance. They would may use explicit destruction and placement new instead (and logicaly it is more correct), but assignment has a chance to be more efficient. I suppose, it is logically redundant requirement "to be assignable" (copy constructable is enough), but stl containers want to be faster and simpler.
Of course, it is possible to implement assignment as explicit destruction+placement new to avoid const_cast hack
Rather than declaring the data-member const, you can make the public surface of the class const, apart from the implicitly defined parts that make it (semi)regular.
class Multiply {
public:
Multiply(double coef) : coef(coef) {}
double operator()(double x) const {
return coef*x;
}
private:
double coef;
};
You basically never want to put a const member variable in a class. (Ditto with using references as members of a class.)
Constness is really intended for your program's control flow -- to prevent mutating objects at the wrong times in your code. So don't declare const member variables in your class's definition, rather make it all or nothing when you declare instances of the class.