为什么由析构函数构造的两个对象被调用三次

时间:2013-04-25 03:09:21

标签: c++ c++11 move-semantics

这是我对一些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;
}

输出:

$ 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

1 个答案:

答案 0 :(得分:12)

您的移动赋值运算符应返回引用:

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

由于您按值返回,但没有return语句,因此您正在调用未定义的行为。您应该像复制赋值运算符一样实现它,当然除了移动资源而不是复制它们之外:

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[]删除动态分配的数组。