This question already has answers here:
Why must the copy assignment operator return a reference/const reference?
(8 answers)
Closed 8 years ago.
I've tried to understand what is the purpose of reference returning in this code ? Is it just because returning reference is much faster than copy or is there something else more important ??
class Container
{
public:
int Elems;
int * data;
Container(int n):Elems(n){data=new int[Elems];}
Container operator= (const Container &rhs);
};
Container & Container:: operator= (const Container & rhs)
{// I deleted the & and I can still compiled and make such things (a=b=c)
if(this!=&rhs)
{
if(data!=NULL)
{
delete [] data;
}
Elems=rhs.Elems;
data=new int[Elems];
for(int i=0;i<Elems;i++)
data[i]=rhs.data[i];
}
return *this;
}
Yes, it's to avoid unneeded copies. In the case of this particular class, though, it's needed for correctness, as there's no proper copy constructor. Default copying instances of this class will result in multiple instances sharing the same data member, and will likely result in multiple deletes.
In C++ function signatures do not depend on the return type, so the return is ignored when overloading.
Before C++11, returning a value instead of a reference would incur in copy overhead.
Related
This question already has answers here:
Why should the assignment operator return a reference to the object?
(4 answers)
Closed 8 years ago.
I have written a class in C++ and have defined assignment operator function:
cplusplus.com recommends following syntax.
check operator= (const check& obj){*cstr = *(obj.cstr); return *this;}
One another syntax is:
void operator= (const check& obj){*cstr = *(obj.cstr);} # Not returning *this
Would you recommend using first method or the second?
Following is my class:
class check {
private:
string * cstr;
public:
int a;
check (string str) { cstr = new string(str);}
check (const check& obj) {cstr = obj.cstr;}
~check() {cout<<"DES"<<endl; delete cstr; }
check operator= (const check& obj){*cstr = *(obj.cstr); return *this;}
void display () { cout<<*cstr<<endl;}
};
int main () {
check da {"one"};
check pa {"two"};
pa = da;
have (pa);
return 0;
}
The usual way of writing the assignment operator is actually
check &operator= (const check& obj){*cstr = *(obj.cstr); return *this;}
i.e., returning a reference to itself. This matches the semantics of assignment for built-in types. Returning check by value may incur an unnecessary copy if the return value is not used. Returning void means you can't write check1 = check2 = check3;.
By the way, check (const check& obj) {cstr = obj.cstr;} is probably wrong. You'd want your copy constructor to make a deep copy and not just copy a pointer. Moreover, I see no reason you need to use a pointer as a class member. If you just store a plain std::string, you can simply use the compiler-generated copy constructor and copy assignment operators.
This question already has answers here:
Difference between returning reference vs returning value C++
(3 answers)
What are the basic rules and idioms for operator overloading?
(8 answers)
Closed 8 years ago.
MyClass& operator=(const MyClass& other)
{
//Implement
return *this;
}
MyClass operator=(const MyClass& other)
{
//Implement
return *this;
}
void operator=(const MyClass& other)
{
//Implement
}
When I test these methods, the result is the same. In almost book I see that the first method(MyClass&) is used more than the second method. what's different between them? Which method is really right and fast? One method return address and the second return value.
When I test these methods, the result is the same.
it depends on how you test your class, ie.:
void foo (MyClass& a);
MyClass a1;
MyClass a2;
foo(a1 = a2);
in case of second operator implementation (returning MyClass), above code (inside foo) will not modify a1 instance, but a temporary value.
In almost book I see that the first method(MyClass&) is used more than
the second method.
and thats correct, its more correct to return reference to *this in assignment operator
what's different between them? Which method is really right and fast?
first version is faster and correct because it does not do any copy of your object, also its more proper because thats how primitive types behave, ie:
int n = 0;
int k = 10;
(n = k) = 1;
std::cout << n;
here on output you will get 1, because (n = k) returns reference to n.
Consider the following code:
struct s
{
const int id;
s(int _id):
id(_id)
{}
};
// ...
vector<s> v; v.push_back(s(1));
I get a compiler error that 'const int id' cannot use default assignment operator.
Q1. Why does push_back() need an assignment operator?
A1. Because the current c++ standard says so.
Q2. What should I do?
I don't want to give up the const specifier
I want the data to be copied
A2. I will use smart pointers.
Q3. I came up with a "solution", which seems rather insane:
s& operator =(const s& m)
{
if(this == &m) return *this;
this->~s();
return *new(this) s(m);
}
Should I avoid this, and why (if so)? Is it safe to use placement new if the object is on the stack?
C++03 requires that elements stored in containers be CopyConstructible and Assignable (see §23.1). So implementations can decide to use copy construction and assignment as they see fit. These constraints are relaxed in C++11. Explicitly, the push_back operation requirement is that the type be CopyInsertable into the vector (see §23.2.3 Sequence Containers)
Furthermore, C++11 containers can use move semantics in insertion operations and do on.
I don't want to give up the const specifier
Well, you have no choice.
s& operator =(const s& m) {
return *new(this) s(m);
}
Undefined behaviour.
There's a reason why pretty much nobody uses const member variables, and it's because of this. There's nothing you can do about it. const member variables simply cannot be used in types you want to be assignable. Those types are immutable, and that's it, and your implementation of vector requires mutability.
s& operator =(const s& m)
{
if(this == &m) return *this;
this->~s();
return *new(this) s(m);
}
Should I avoid this, and why (if so)? Is it safe to use placement new if the object is on the stack?
You should avoid it if you can, not because it is ill-formed, but because it is quite hard for a reader to understand your goal and trust in this code. As a programmer, you should aim to reduce the number of WTF/line of code you write.
But, it is legal. According to
[new.delete.placement]/3
void* operator new(std::size_t size, void* ptr) noexcept;
3 Remarks: Intentionally performs no other action.
Invoking the placement new does not allocate or deallocate memory, and is equivalent to manually call the copy constructor of s, which according to [basic.life]/8 is legal if s has a trivial destructor.
Ok,
You should always think about a problem with simple steps.
std::vector<typename T>::push_back(args);
needs to reserve space in the vector data then assigns(or copy, or move) the value of the parameter to memory of the vector.data()[idx] at that position.
to understand why you cannot use your structure in the member function std::vector::push_back , try this:
std::vector<const int> v; // the compiler will hate you here,
// because this is considered ill formed.
The reason why is ill formed, is that the member functions of the class std::vector could call the assignment operator of its template argument, but in this case it's a constant type parameter "const int" which means it doesn't have an assignment operator ( it's none sense to assign to a const variable!!).
the same behavior is observed with a class type that has a const data member. Because the compiler will delete the default assignment operator, expel
struct S
{
const int _id; // automatically the default assignment operator is
// delete i.e. S& operator-(const S&) = delete;
};
// ... that's why you cannot do this
std::vector<S> v;
v.Push_back(S(1234));
But if you want to keep the intent and express it in a well formed code this is how you should do it:
class s
{
int _id;
public:
explicit s(const int& id) :
_id(id)
{};
const int& get() const
{
return _id;
}; // no user can modify the member variable after it's initialization
};
// this is called data encapsulation, basic technique!
// ...
std::vector<S> v ;
v.push_back(S(1234)); // in place construction
If you want to break the rules and impose an assignable constant class type, then do what the guys suggested above.
Q2. What should I do?
Store pointers, preferably smart.
vector<unique_ptr<s>> v;
v.emplace_back(new s(1));
It's not really a solution, but a workaround:
#include <vector>
struct s
{
const int id;
s(int _id):
id(_id)
{}
};
int main(){
std::vector<s*> v;
v.push_back(new s(1));
return 0;
}
This will store pointers of s instead of the object itself. At least it compiles... ;)
edit: you can enhance this with smart c++11 pointers. See Benjamin Lindley's answer.
Use a const_cast in the assignment operator:
S& operator=(const S& rhs)
{
if(this==&rhs) return *this;
int *pid=const_cast<int*>(&this->id);
*pid=rhs.id;
return *this;
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 months ago.
Improve this question
I'm learning c++ and I recently learned (here in stack overflow) about the copy-and-swap idiom and I have a few questions about it. So, suppose I have the following class using a copy-and-swap idiom, just for example:
class Foo {
private:
int * foo;
int size;
public:
Foo(size_t size) : size(size) { foo = new int[size](); }
~Foo(){delete foo;}
Foo(Foo const& other){
size = other.size;
foo = new int[size];
copy(other.foo, other.foo + size, foo);
}
void swap(Foo& other) {
std::swap(foo, other.foo);
std::swap(size, other.size);
}
Foo& operator=(Foo g) {
g.swap(*this);
return *this;
}
int& operator[] (const int idx) {return foo[idx];}
};
My question is, suppose I have another class that have a Foo object as data but no pointers or other resources that might need custom copying or assignment:
class Bar {
private:
Foo bar;
public:
Bar(Foo foo) : bar(foo) {};
~Bar(){};
Bar(Bar const& other) : bar(other.bar) {};
Bar& operator=(Bar other) {bar = other.bar;}
};
Now I have a series of questions:
Are the methods and constructors as implemented above for the Bar class safe? Having used the copy-and-swap for Foo make me sure that no harm can be done when assigning or copying Bar?
Passing the argument by reference in the copy constructor and in swap is mandatory?
Is it right to say that when the argument of operator= is passed by value, the copy constructor is called for this argument to generate a temporary copy of the object, and that it is this copy which is then swapped with *this? If I passed by reference in operator= I would have a big problem, right?
Are there situations in which this idiom fails to provide complete safety in copying and assigning Foo?
As much as possible, you should initialize the members of your class in the initializer list. That will also take care of the bug I told you about in the comment. With this in mind, your code becomes:
class Foo {
private:
int size;
int * foo;
public:
Foo(size_t size) : size(size), foo(new int[size]) {}
~Foo(){delete[] foo;} // note operator delete[], not delete
Foo(Foo const& other) : size(other.size), foo(new int[other.size]) {
copy(other.foo, other.foo + size, foo);
}
Foo& swap(Foo& other) {
std::swap(foo, other.foo);
std::swap(size, other.size);
return *this;
}
Foo& operator=(Foo g) {
return swap(g);
}
int& operator[] (const int idx) {return foo[idx];}
};
and
class Bar {
private:
Foo bar;
public:
Bar(Foo foo) : bar(foo) {};
~Bar(){};
Bar(Bar const& other) : bar(other.bar) { }
Bar& swap(Bar &other) { bar.swap(other.bar); return *this; }
Bar& operator=(Bar other) { return swap(other); }
}
which uses the same idiom throughout
note
as mentioned in a comment on the question, Bar's custom copy constructors etc. are unnecessary, but we'll assume Bar has other things as well :-)
second question
Passing by reference to swap is needed because both instances are changed.
Passing by reference to the copy constructor is needed because if passing by value, you'd need to call the copy constructor
third question
yes
fourth question
no, but it is not always the most efficient way of doing things
1 - Are the methods and constructors as implemented above for the Bar class safe? Having used the copy-and-swap for Foo make me sure that no harm can be done when assigning or copying Bar?
Regarding the copy-ctor: that's always safe (all-or-nothing). It either completes (all), or it throws an exception (nothing).
If your class is only made up of one member (i.e. no base classes as well), the assignment operator will be just as safe as that of the member's class. If you have more then one member, the assignment operator will no longer be "all or nothing". The second member's assignment operator could throw an exception, and in that case the object will be assigned "half way". That means you need to implement copy-and-swap again in the new class to get "all or nothing" assignment.
However it will still be "safe", in the sense that you won't leak any resources. And of course the state of each member individually will be consistent - just the state of the new class won't be consistent, because one member was assigned and the other was not.
2 - Passing the argument by reference in the copy constructor and in swap is mandatory?
Yes, passing by reference is mandatory. The copy constructor is the one that copies objects, so it cannot take it's argument by value, since that would mean the argument has to be copied. This would lead to infinite recursion. (The copy-ctor would be called for the argument, which would mean calling the copy-ctor for the argument, which would mean ...). For swap, the reason is another: if you were to pass the argument by value, you could never use swap to really exchange the contents of two objects - the "target" of the swap would be a copy of the object originally passed in, which would be destroyed immediately.
3 - Is it right to say that when the argument of operator= is passed by value, the copy constructor is called for this argument to generate a temporary copy of the object, and that it is this copy which is then swapped with *this? If I passed by reference in operator= I would have a big problem, right?
Yes, that's right. However it's also quite common to take the argument by reference-to-const, construct a local copy and then swap with the local copy. The by reference-to-const way has some drawbacks however (it disables some optimizations). If you're not implementing copy-and-swap though, you should probably pass by reference-to-const.
4 - Are there situations in which this idiom fails to provide complete safety in copying and assigning Foo?
None that I know of. Of course one can always make things fail with multi-threading (if not properly synchronized), but that should be obvious.
This is a classic example of where following an idiom leads to unnecessary performance penalties (premature pessimization). This isn't your fault. The copy-and-swap idiom is way over-hyped. It is a good idiom. But it should not be followed blindly.
Note: One of the most expensive things you can do on a computer is allocate and deallocate memory. It is worthwhile to avoid doing so when practical.
Note: In your example, the copy-and-swap idiom always performs one deallocation, and often (when the rhs of the assignment is an lvalue) one allocation as well.
Observation: When size() == rhs.size(), no deallocation or allocation need be done. All you have to do is a copy. This is much, much faster.
Foo& operator=(const Foo& g) {
if (size != g.size)
Foo(g).swap(*this);
else
copy(other.foo, other.foo + size, foo);
return *this;
}
I.e. check for the case where you can recycle resources first. Then copy-and-swap (or whatever) if you can't recycle your resources.
Note: My comments do not contradict the good answers given by others, nor any correctness issues. My comment is only about a significant performance penalty.
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I am studying for my midterm exam. There is going to be a question about setting up an array dynamically, and maybe doing a copy constructor, a destructor and overloading the assignment operator. Can you please verify if I am correct. Also I don't understand what overloading the assignment operator means. Can you help me out with this?
class A
{
int* myArray; //basically I created a pointer called myArray,
A() //are my copy constructors correct? A(), and A(int size)?
{
myArray = 0;
}
A(int size)
{
myArray = new int[size];
}
~A() // I think my destructor is correct
{
delete [] myArray;
}
Can you check my code please? Also how do I overload assignment operator?
Thanks in advance.
The copy constructor is used for creation of object based on another's instance of the same type. You don't have such. You can define it using code like this:
A(const A &other)
{
myArray = new int[other._size];
_size = other._size;
memcpy(myArray, other.myArray, sizeof(int) * _size);
}
You should change your class, so it will store _size of array, you also need to change visibility of your constructors and destructor to public.
The overloaded assignment operator should look like this:
const A &operator=(const A &other)
{
if(this == &other) return *this; // handling of self assignment, thanks for your advice, arul.
delete[] myArray; // freeing previously used memory
myArray = new int[other._size];
_size = other._size;
memcpy(myArray, other.myArray, sizeof(int) * _size);
return *this;
}
You also can add a check of equality of array sizes in this assignment operator, so you will reuse your dynamic array without unnecessary reallocations of memory.
You have correctly defined 2 overloaded constructors and a destructor.
However, you haven't defined an explicit copy constructor properly.
Normally the compiler will generate one for you, and this is called an implicit copy constructor.
The problem with the auto-generated implicit copy constructor in your particular case is that it will only perform a shallow copy of myArray, where it shares the same pointer value but hasn't allocated its own section of memory for myArray.
This means if you delete myArray in the original object, it will affect the copy which is most likely not what you want.
Defining an explicit copy constructor like this will help:
A(const A& copy)
: _size(copy.size), myArray(new int[copy.size])
{
// #include <algorithm> for std::copy
std::copy(copy.data, copy.data + copy.size, data);
}
(Source: Copied from Wikipedia)
If you define the copy constructor like this, you should not need to overload the assignment operator. If you create a new object, and assign it to the first object you created, you will successfully create an independent copy of the first object.
Edit: From this article:
The copy assignment operator differs
from the copy constructor in that it
must clean up the data members of the
assignment's target (and correctly
handle self-assignment) whereas the
copy constructor assigns values to
uninitialized data members.
when dealing with object copy and dynamic memory allocation it's a good idea to use a swap helper function
A(const A& other)
: myArray(0)
, _size(0)
{
if(this != &other) {
A my_tmp_a(other._size);
std::copy(&other[0], &other[other._size], &my_tmp_a[0]);
swap(my_tmp_a);
}
}
const A& operator=(const A& other)
{
if(this == &other) return *this;
A my_tmp_a(other._size);
std::copy(&other[0], &other[other._size], &my_tmp_a[0]);
swap(my_tmp_a);
return *this;
}
void swap(const A& other) {
int* my_tmp_array = this.myArray;
this.myArray = other.myArray;
other.myArray = my_tmp_array;
int my_tmp_size = this._size;
this._size = other._size;
other._size = my_tmp_size;
}
Please make sure define three functions when you want to define one of them. Its called all or none rule
They are:
1) copy constructor.
2) assignment operator.
3) destructor.
Partial answer: overloading a function involves creating different versions of that function which accept different numbers or kinds of arguments. So overloading the assignment operator would involve creating several functions for the assignment operator which allow you to assign objects of various types to a variable of type A.