After doing some experimentation with move semantics with an array type I created, I am wondering why Microsoft's C++ compiler calls the move constructor when returning from a method by value whilst the Clang compiler elides the copy all together?
Is this correct or incorrect behaviour from Clang? or correct behaviour from Microsoft?
#include <algorithm>
#include <iostream>
template<typename T>
class Array {
public:
template<typename E>
class ArrayIterator {
public:
ArrayIterator(Array<E>& elements, int index) : position_(index), elements_(elements) {
}
T& operator * () {
return elements_[position_];
}
ArrayIterator& operator++ () {
position_++;
return *this;
}
ArrayIterator operator++ (int) {
return ArrayIterator(elements_, ++position_);
}
bool operator != (ArrayIterator const & other) {
return position_ != other.position_;
}
private:
int position_;
Array<E>& elements_;
};
typedef ArrayIterator<T> iterator;
Array();
explicit Array(int size);
~Array();
Array(const Array& other);
Array(Array&& other);
Array<T>& operator = (Array other);
T& operator[](int index);
int size() const;
iterator begin();
iterator end();
private:
void internal_swap(Array& other);
T *elements_;
int length_;
};
template<typename T>
Array<T>::Array() {
length_ = 0;
elements_ = 0;
}
template<typename T>
Array<T>::Array(int size) {
elements_ = new T[size];
length_ = size;
}
template<typename T>
Array<T>::~Array() {
delete[] elements_;
std::cout << "Destroy...." << std::endl;
}
template<typename T>
Array<T>::Array(const Array<T>& other) {
std::cout << "copy ctor" << std::endl;
length_ = other.size();
T *elements = new T[size()];
std::copy(other.elements_, other.elements_ + other.size(), elements);
elements_ = elements;
}
template<typename T>
Array<T>::Array(Array<T>&& other) {
std::cout << "move ctor" << std::endl;
length_ = other.size();
T* oelements = other.elements_;
other.elements_ = 0;
this->elements_ = oelements;
}
template<typename T>
Array<T>& Array<T>::operator = (Array other) {
internal_swap(other);
return *this;
}
template<typename T>
T& Array<T>::operator[](int index) {
return elements_[index];
}
template<typename T>
int Array<T>::size() const {
return length_;
}
template<typename T>
typename Array<T>::iterator Array<T>::begin() {
return iterator(*this, 0);
}
template<typename T>
typename Array<T>::iterator Array<T>::end() {
return iterator(*this, size());
};
template<typename T>
void Array<T>::internal_swap(Array& other){
T* oelements = other.elements_;
other.elements_ = this->elements_;
this->elements_ = oelements;
}
Array<int> get_values(int x);
int main(int argc, const char *argv[]) {
Array<int> a = get_values(2);
for (Array<int>::iterator i = a.begin(); i != a.end(); ++i) {
std::cout << *i << std::endl;
}
return 0;
}
Array<int> get_values(int x) {
Array<int> a(10);
if(x == 1) return a;
for (int i = 0; i <= 9; i++) {
a[i] = 1 + i;
}
return a;
}
if(x == 1) return a;
in yourget_values()
function body, NRVO is applied. It seems like theif
statement prevents NRVO... – Pagel