2012-03-26 69 views
6

在我用創建的數組類型對移動語義進行了一些實驗之後,我想知道爲什麼微軟的C++編譯器在通過值方法返回時調用移動構造函數,而Clang編譯器忽略了全部複製一起?在MS C++ vs Clang中移動語義

這是來自Clang的正確或不正確的行爲?或糾正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; 
} 
+0

MSVC和Clang的編譯器標誌是什麼? – Xeo 2012-03-26 02:08:06

+0

XCode 4.3和VS 2010的所有默認值。 – 2012-03-26 02:36:05

+2

是的,但是,VS中的默認值是調試模式,也就是說沒有優化...所以我們來說說它有點不同:你是否在發佈模式下編譯了兩個版本? – Xeo 2012-03-26 03:22:31

回答

8

複製省略是少有的優化,在標準允許不同的觀察到的行爲(不屬於AS-如果統治之下)之一,但不是不確定的行爲。

是否在此上下文中調用或刪除任何副本或移動構造函數是未指定的,並且不同的編譯器可以有不同的表現,並且兩者都是正確的。

+0

我認爲移動Ctor是首選? – 2012-03-26 03:02:21

+3

@Blair:哦,不,在合適的地方建造這個物品,肯定會喜歡移動它並摧毀舊的。 – 2012-03-26 03:28:30

+0

因此,只有在不能使用RVO/NRVO的情況下,您的說法纔會使用?即最後的手段? – 2012-03-26 05:25:20