Are the following assignment and copy move constructors the most efficient?
if anybody have other way please tell me?
I mean what bout std::swap? and calling assignment through copy constructor is safe in the code below?
#include <iostream>
#include <functional>
#include <algorithm>
#include <utility>
using std::cout;
using std::cin;
using std::endl;
using std::bind;
class Widget
{
public:
Widget(int length)
:length_(length),
data_(new int[length])
{
cout<<__FUNCTION__<<"("<<length<<")"<<endl;
}
~Widget()
{
cout<<endl<<__FUNCTION__<<"()"<<endl;
if (data_)
{
cout<<"deleting source"<<endl;
}
else
{
cout<<"deleting Moved object"<<endl;
}
cout<<endl<<endl;
}
Widget(const Widget& other)
:length_(other.length_),
data_(new int[length_])
{
cout<<__FUNCTION__<<"(const Widget& other)"<<endl;
std::copy(other.data_,other.data_ + length_,data_);
}
Widget(Widget&& other)
/*
:length_(other.length_),
data_(new int[length_])*/
{
cout<<__FUNCTION__<<"(Widget&& other)"<<endl;
length_ = 0;
data_ = nullptr;
std::swap(length_,other.length_);
std::swap(data_,other.data_);
}
Widget& operator = (Widget&& other)
{
cout<<__FUNCTION__<<"(Widget&& other)"<<endl;
std::swap(length_,other.length_);
std::swap(data_,other.data_);
return *this;
}
Widget& operator = (const Widget& other)
{
cout<<__FUNCTION__<<"(const Widget& other)"<<endl;
Widget tem(other);
std::swap(length_,tem.length_);
std::swap(data_,tem.data_);
return *this;
}
int length()
{
return length_;
}
private:
int length_;
int* data_;
};
int main()
{
{
Widget w1(1);
Widget w2(std::move(Widget(2)));
w1 = std::move(w2);
}
cout<<"ENTER"<<endl;
cin.get();
return 0;
}
Looks fine from an efficiency POV, but contains an awful lot of duplicated code. I’d
swap()operator for your class.length_anddata_where they are declared.You might want to use
std::memcpyinstead ofstd::copysince you’re dealing with a raw array anyway. Some compilers will do that for you, but probably not all of them…Here’s a de-duplicated version of your code. Note how there is only one place which needs to know how two instances of
Widgetare swapped. And only one place which knows how to allocate a Widget of a given size.Edit: You usually also want to use argument-dependent lookup to locate swap, just in case you ever have non-primitive members.
Edit: Integrated @Philipp’s suggestion of making the assignment operator take it’s argument by value. That way, it acts as both move assignment and copy assignment operator. In the move case, not that if you pass a temporary, it won’t be copied, since the move constructor, not the copy constructor will be used to pass the argument.
Edit: C++11 allows non-cost members to be called on rvalues for compatibility with previous versions of the standard. This allows weird code like
Widget(...) = someWidgetto compile. Makingoperator=require an lvalue forthisby putting&after the declaration prevents that. Note though that the code is correct even without that restriction, but it nevertheless seems like a good idea, so I added it.Edit: As Guillaume Papin pointed out, the destructor should use
delete[]instead of plaindelete. The C++ standard mandates that memory allocated vianew []be deleted viadelete [], i.e. it allowsnew' andnew []` to use different heaps.