mardi 24 mars 2020

Pimpl and copy-and-swap idiom

I've seen many questions and answers regarding the copy-and-swap idiom (when combined with the pimpl idiom). I recently implemented a class using both, and ended up with some questions:

1 In case of a pimpled class, do I (still) need a non-member friend swap function (as described in this question)? As the question is already 10 years old, are there any changes regarding this?

2 In case of a pimpl (based on a unique ptr), wouldn't the standard std::swap work just fine? (In which case I wouldn't need a custom swap)

3 I have all my members in a pimpl struct. In case everything is copyable, coulnd't I just use the default copy constructor?

// trial.h
class Trial
{
public:
    Trial(ID a_ID = UNKNOWN_ID);
    Trial(const Trial& rhs);
    Trial(Trial&& rhs) noexcept;
    ~Trial();
    Trial& operator=(Trial rhs);

    void swap(Trial& rhs);
    inline ID GetID() const;

private:
    struct TrialImpl;
    std::unique_ptr<TrialImpl> m_Impl;
};

// trial.cpp
struct Trial::TrialImpl
{
    TrialImpl(ID a_ID) : 
        m_ID(a_ID){}

    TrialImpl(const TrialImpl& rhs)
    {
        // make a deep copy (perhaps use default copy constructor)
        m_ID = rhs.m_ID;
        m_Frames = rhs.m_Frames;
    }

    ID m_ID;
    std::vector<Frame> m_Frames;
};

Trial::Trial(ID a_ID) :
    m_Impl(std::make_unique<TrialImpl>(a_ID))
{
}

Trial::Trial(const Trial& rhs) :
    m_Impl(std::make_unique<TrialImpl>(*rhs.m_Impl))
{
}

Trial::Trial(Trial&&) noexcept = default;
Trial::~Trial() = default;

Trial& Trial::operator=(Trial rhs)
{
    swap(rhs);
    return *this;
}

void Trial::swap(Trial& rhs)
{
    // we can just let std::swap swap the unique pointers
    std::swap(m_Impl, rhs.m_Impl);
}

ID Trial::GetID() const
{
    return m_Impl->m_ID;
}

Aucun commentaire:

Enregistrer un commentaire