2013-04-25 1 views
4

다음은 C++ 11 연구용 예제를 구현 한 것입니다. 모든 생성자와 소멸자가 콘솔로 출력하도록했습니다. 그러나 놀랍게도 두 번 호출되지만 생성자는 세 번 호출됩니다.왜 파괴자에 의해 생성 된 두 객체가 세 번 호출되는지

예기치 않은 것 같습니다. 0x7fff5fbff6d0입니다. 이 객체가 생성되면? 하지만 생성자 호출이 연관되지 않은 이유는 무엇입니까?

왜 이런 일이 발생하고 있습니까?

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; 
} 

출력 :

ArrayWrapper<T>& operator=(ArrayWrapper&& other) 
//   ^

당신이 값으로 반환이 있지만 return 문이 없기 때문에, 당신이있어 :

$ 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 

답변

12

귀하의 이동 할당 연산자는 참조를 반환해야 정의되지 않은 동작을 호출합니다. 당신은 물론 자원을 이동하는 대신이를 복사를 제외하고, 복사 할당 연산자처럼 구현해야합니다 :

또한
ArrayWrapper<T>& operator=(ArrayWrapper&& other){ 
    if(this != &other){ 
     delete[] data_; 
     size_ = other.size_; 
     data_ = other.data_; 
     other.size_ = 0; 
     other.data_ = nullptr; 
    } 
    return *this; 
} 

는 동적으로 할당 된 배열을 삭제 delete[]의 사용을 확인합니다.

+1

+1 반환 유형이 고정되고'return * this;'가 추가되면 생성자 호출은 2 개와 일치하는 소멸자 호출이 2 개 있습니다. – Praetorian

+0

나는 그것을 시험해 보았다. – xiaochuanQ

+0

이동 할당 연산자가 'other.size_ = 0;'을 설정하려고합니다. –

관련 문제