首页 > 解决方案 > 如何使用移动构造函数释放内存

问题描述

我正在尝试创建自己的向量,这是一个介绍我遇到的问题的最小示例:

class DemoVector {
public:
    DemoVector() : capacity_(1), size_(0) {
        data_ = new int[1];
    }

    DemoVector(DemoVector&& rhs) {
        data_ = std::move(rhs.data_);
        size_ = rhs.size_;
        capacity_ = rhs.capacity_;
    }

    ~DemoVector() {
        delete[] data_;
    }

    void PushBack(const int &v) {
        // doesn't matter
    }

private:
    int *data_;
    size_t capacity_;
    size_t size_;
};

测试:

TEST_CASE("Test") {
    DemoVector b;
    b.PushBack(1);
    DemoVector c(std::move(b));
}

我有一个问题,我明白为什么。我有两个指向同一内存的对象。第二个析构函数尝试释放已被第一个析构函数释放的内存。

但我不知道如何解决它。谢谢您的帮助。

标签: c++

解决方案


std::move(rhs.data_)实际上并没有移动任何东西。std::move无非是一个有名的演员表。它产生一个允许移动语义发生的右值引用。但是对于原始类型,它只是一个复制操作。指针正在被复制,因此您最终会得到两个包含相同地址的指针。由于您不希望源对象仍然指向同一个缓冲区,因此只需修改它。这就是为什么移动语义是围绕非常量引用构建的。

移动构造函数现在很常见,因此有一个标准实用程序 (C++14) 可以帮助编写它们,使代码表现得更符合您的预期。是std::exchange。你可以简单地写

DemoVector(DemoVector&& rhs)
  : data_(std::exchange(rhs.data_, nullptr))
  , size_(std::exchange(rhs.size_ , 0))
  , capacity_(std::exchange(rhs.capacity_ , 0))
{}

并且所有值都得到了适当的调整。std::exchange修改其第一个参数以保存第二个参数的值。最后,它返回第一个参数的旧值。在单行初始化中移动值非常方便。


推荐阅读