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

Why two object constructed by destructors are called for three times

本文关键字:对象 调用 三次 两个 析构函数 为什么      更新时间:2023-10-16

下面是我实现的一些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

你的move赋值运算符应该返回一个引用:

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