Here is my implementation of some C++11 study examples. I let all the constructors and destructor to print to console. But surprisingly, I get constructor called twice but destructor three times.
The one seems unexpected is at 0x7fff5fbff6d0. When this object is created? But why no constructor call is associated?
Why this is happening?
template<typename T>
class ArrayWrapper{
public:
ArrayWrapper():data_(nullptr), size_(0){
cout << "Default ctor called "<< this <<endl;
}
ArrayWrapper(size_t n, const T& val) : data_(new T[n]), size_(n){
cout << "ctor_n_val called "<< this << endl;
for_each(data_, data_+size_, [&](T& elem){ elem=val; });
}
ArrayWrapper(const ArrayWrapper& other): data_(new T[other.size_]), size_(other.size_)
{
cout << "copy ctor called "<< this <<endl;
copy(other.data_, other.data_+other.size_, data_);
}
ArrayWrapper(ArrayWrapper&& other): data_(other.data_), size_(other.size_)
{
cout << "move ctor called"<<endl;
other.data_ = nullptr;
other.size_ = 0;
}
ArrayWrapper<T>& operator=(const ArrayWrapper& other){
cout << "copy assignment called" <<endl;
if(this != &other){
delete data_;
data_ = new T[other.size_];
copy(other.begin(), other.end(), begin());
size_ = other.size_;
}
return *this;
}
ArrayWrapper<T> operator=(ArrayWrapper&& other){
cout << "move assignment called " <<this << " <- " <<&other <<endl;
swap(size_, other.size_);
swap(data_, other.data_);
}
~ArrayWrapper(){
cout <<"Destroying " << this << " Size " << size_ <<endl;
}
typedef T* iterator;
typedef const T* const_iterator;
T* begin() {
return data_;
}
T* end(){
return data_ + size_;
}
const T* begin() const {
return data_;
}
const T* end() const {
return data_ + size_;
}
const T* cbegin() const {
return data_;
}
const T* cend() const {
return data_ + size_;
}
size_t size(){
return size_;
}
public:
T* data_;
size_t size_;
};
template<typename T>
ArrayWrapper<T> make_array(size_t n, const T& val){
cout <<"Factory method called"<<endl;
return ArrayWrapper<T>(n, val);
}
template<typename T>
std::ostream& operator<<(std::ostream& os, const ArrayWrapper<T>& arr){
for(const T& elem: arr){ os << elem << ", ";}
return os;
}
int main(){
size_t n = 10;
ArrayWrapper<int> a4(n, 1);
a4 = make_array(n, 4); // move assignment:
cout << "A4: " << a4 << endl;
}
Output:
$ g++-mp-4.8 -std=c++11 move.cpp
$ ./a.out
ctor_n_val called 0x7fff5fbff6b0
Factory method called
ctor_n_val called 0x7fff5fbff6e0
move assignment called 0x7fff5fbff6b0 <- 0x7fff5fbff6e0
Destroying 0x7fff5fbff6d0 Size 0
Destroying 0x7fff5fbff6e0 Size 10
A4: 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
Destroying 0x7fff5fbff6b0 Size 10
Your move assignment operator should return a reference:
ArrayWrapper<T>& operator=(ArrayWrapper&& other)
// ^
Since you have it returning by value, but there is no return
statement, you’re invoking undefined behaviour. You should implement it like the copy assignment operator, except of course moving resources instead of copying them:
ArrayWrapper<T>& operator=(ArrayWrapper&& other){
if(this != &other){
delete[] data_;
size_ = other.size_;
data_ = other.data_;
other.size_ = 0;
other.data_ = nullptr;
}
return *this;
}
Also, note the use of delete[]
to delete dynamically allocated arrays.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With