带有向量的类构造函数中的析构函数调用

Posted

技术标签:

【中文标题】带有向量的类构造函数中的析构函数调用【英文标题】:Destructor call in a class constructor with a vector 【发布时间】:2020-01-26 13:58:45 【问题描述】:

我有以下类,它简单地包装了一个数组,并用构造函数向它添加了一些元素:

class myArray 
public:
    myArray();
    myArray(int a, int b);
    myArray(int a, int b, int c);
    myArray(myArray&& emplace);

    ~myArray();

    int& operator [](int id);

private:
    int *data;
;

myArray::myArray() 
    data = new int[1];
    data[0] = 0;


myArray::myArray(int a, int b) 
    data = new int[3];
    data[0] = 0;
    data[1] = a;
    data[2] = b;


myArray::myArray(int a, int b, int c) 
    data = new int[4];
    data[0] = 0;
    data[1] = a;
    data[2] = b;
    data[3] = c;


myArray::~myArray() 
    std::cout << "Destructor"<<std::endl;
    delete[] data;


int& myArray::operator [](int id) 
    return data[id];


myArray::myArray(myArray&& emplace) : data(std::move(emplace.data)) 

此外,我还有第二类,其中包含第一类元素的向量 (myArray)。

class Queue 
public:
    Queue();

private:
    std::vector<myArray> _queue;
;

Queue::Queue 
    _queue.reserve(1000);
    for(int a = 0; a < 10; a++)
        for(int b = 0; b < 10; b++)
            for(int c = 0; c < 10; c++)
                        _queue.emplace_back(a,b,c);

我的问题是:为什么在 Queue 构造函数的末尾调用 myArray 元素的析构函数? Queue 对象在我的主程序中仍然存在,但 myArray 的析构函数释放了分配的内存,因此我得到了分段错误。

有没有办法避免调用析构函数,或者直到队列对象生命周期结束时才调用它?

【问题讨论】:

myArray 对象被复制到向量中,存在双重删除问题。结帐规则三 @billz Queue 构造函数中没有 myArray 的复制。不过,队列可能被复制到其他地方。 I cannot reproduce it 【参考方案1】:

您的移动构造函数没有将移动对象上的 data 设置为 null,因此当移动对象被破坏时,它会尝试释放数据。

如果你有 c++14,你可以使用std::exchange 来实现这个:

myArray::myArray(myArray&& emplace)
 : datastd::exchange(emplace.data, nullptr))

否则你需要这样做:

myArray::myArray(myArray&& emplace)
 : dataemplace.data)

  emplace.data = nullptr;

移动构造函数将由std::vector 调用,因为它会在您调用emplace_back 时重新分配以增加其容量。执行类似于以下步骤:

    分配新内存来保存元素 使用在新内存中从前一个内存中的元素放置新元素来移动构造 销毁之前内存中的元素 释放之前的内存

【讨论】:

谢谢,修复了分段错误!如果我正确理解向量元素的内存被分配和释放两次?第一次在 Queue 构造函数的末尾,第二次在 Queue 解构函数的调用? 不,当您调用 emplace_back 时,您的对象被构​​造,当您擦除元素或向量被破坏时,它被破坏。此外,当向量改变容量时,将使用所有现有元素的复制或移动构造函数创建新元素,然后销毁所有现有元素。

以上是关于带有向量的类构造函数中的析构函数调用的主要内容,如果未能解决你的问题,请参考以下文章

继承和组合混搭的情况下,构造和析构函数的调用顺序

子类的构造函数,子类的析构函数,子类型关系

虚析构函数

在构造函数中调用的成员变量的析构函数 - 编译器错误?

[剑指offer]面试题48:不能被继承的类

11.8 C++构造函数小节