复制语义和向量

6 c++ deep-copy copy-constructor assignment-operator

我正在处理分配内存供内部使用的对象。目前,它们不可复制。

例如

class MyClass
{
public:
    MyClass() { Store = new int; }
    ~MyClass() { delete Store; }

private:
    int* Store;
};
Run Code Online (Sandbox Code Playgroud)

我想添加允许分配所需的内容,既具有复制语义又具有移动语义,并且还能够将它们存储在向量中(具有移动语义)。我不想使用智能指针,并希望保持简单。

我应该定义哪些类成员?如何强制复制分配或移动分配?按值或按引用传递对象时将执行哪个副本?C++ 的连续版本之间的实现会有所不同吗?

例如

MyClass A, B;
A = B; // How to force copy or move ?
std::vector<MyClass> V = { A, B };
Run Code Online (Sandbox Code Playgroud)

tbx*_*are 0

您询问了向量,所以...这是 class tbx::Vector。我把它写成练习。其设计遵循Arthur O'Dwyer在 CppCon 2019 上的演讲。请参阅标题为“回归基础:RAII 和零规则”的 YouTube 视频。

为了更密切地关注您询问的复制语义,我只包含了五个“特殊”成员函数,以及其他几个成员和成员函数reserve和swap。虽然类Vector实现了几乎所有的接口std::vector,但是其他的功能这里没有出现。

我留下了一些钩子,您可以在操作符尝试分配失败的情况下插入所需的任何代码new。

这并不打算作为生产代码。首先,为什么要重新发明轮子?其次,有很多优化被省略了。第三,一些功能被省略了,例如,我没有提供完整的ctor补充或对分配器的支持。

template< typename T >
class Vector
{
public:
    using value_type = T;
    using size_type = std::size_t;
    using iterator = value_type*;
    using const_iterator = value_type const*;

private:
    value_type* data_{ nullptr };
    size_type capacity_{};
    size_type size_{};
    enum : size_type { zero, one };

public:
    Vector() noexcept
        = default;

    explicit Vector(size_type const size)
        : data_{ nullptr }, capacity_{ size }, size_{ size }
    {
        if (zero < size)
        {
            try { data_ = new value_type[size]; }
            catch (std::bad_alloc const&) { throw; }
        }
    }

    Vector (Vector const& that)
        : data_{ nullptr }
        , capacity_{ that.size_ }  // "shrink to fit"
        , size_{ that.size_ }
    {
        if (that.size_ != zero)
        {
            try { data_ = new value_type[that.size_]; }
            catch (std::bad_alloc const&) { throw; }
            std::copy(that.data_, that.data_ + size_, data_);
        }
    }

    Vector (Vector&& that) noexcept
        : data_     { std::exchange(that.data_, nullptr)  }
        , capacity_ { std::exchange(that.capacity_, zero) }
        , size_     { std::exchange(that.size_, zero)     }
    {}

    ~Vector() {
        delete[] data_;
    }

    Vector& operator=(Vector that) noexcept {
        swap(that);
        return *this;
    }

    void reserve(size_type const capacity) {
        if (capacity_ < capacity) {
            value_type* p{ nullptr };
            try { p = new value_type[capacity]; }
            catch (std::bad_alloc const&) { throw; }
            if (data_ != nullptr)
                std::copy(data_, data_ + size_, p);
            capacity_ = capacity;
            std::swap(data_, p);
            delete[] p;
        }
    }

    void swap(Vector& that) noexcept {
        using std::swap;
        swap(capacity_, that.capacity_);
        swap(size_, that.size_);
        swap(data_, that.data_);
    }

    friend void swap(Vector& a, Vector& b) noexcept {
        a.swap(b);
    }
};
Run Code Online (Sandbox Code Playgroud)