gpt4 book ai didi

c++ - 在基类和派生类中 copy-and-swap

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:10:38 26 4
gpt4 key购买 nike

我最近读到 copy & swap现在我正在尝试在基类和派生类中实现 ctors。我的基类和派生类中都有四个构造函数,但是我不确定如何实现派生类的赋值运算符。

explicit Base(int i) : m_i{i} {}
Base(const Base & other) : m_i{other.m_i}
Base(Base && other) : Base(0) { swap(*this, other); }
Base & operator=(Base other) { swap(*this, other); return *this; }
friend void swap(Base & a, Base & b) noexcept {
using std::swap;
swap(a.m_i, b.m_i);
}

explicit Derived(int j) : Base(42), m_j(j) {}
Derived(const Derived & other) : Derived(other.m_j) {}
Derived(Derived && other) : Derived(other.m_j) { swap(*this, other); }
Derived & operator=(Derived other) { /*???*/ }
friend void swap(Derived & a, Derived & b) noexcept {
using std::swap;
swap(a.m_j, b.m_j);
}

最佳答案

尽可能考虑使用 = default。如果我们谈论公共(public)继承,那么您确实还需要一个虚拟析构函数。

这是使用复制/交换样式时您的 Base 的样子:

class Base
{
int m_i;
public:
virtual ~Base() = default;
Base(const Base& other) = default;
Base& operator=(Base other) noexcept
{
swap(*this, other);
return *this;
}
Base(Base&& other) noexcept
: Base(0)
{
swap(*this, other);
}

explicit Base(int i) noexcept
: m_i{i}
{}

friend void swap(Base& a, Base& b) noexcept
{
using std::swap;
swap(a.m_i, b.m_i);
}
};

与您所拥有的唯一区别是我添加了虚拟析构函数,并使用 = default 作为复制构造函数。

现在对于 Derived:

class Derived
: public Base
{
int m_j;
public:
Derived(const Derived& other) = default;
Derived& operator=(Derived other) noexcept
{
swap(*this, other);
return *this;
}
Derived(Derived&& other) noexcept
: Derived(0)
{
swap(*this, other);
}

explicit Derived(int j) noexcept
: Base(42)
, m_j{j}
{}

friend void swap(Derived& a, Derived& b) noexcept
{
using std::swap;
swap(static_cast<Base&>(a), static_cast<Base&>(b));
swap(a.m_j, b.m_j);
}
};

我让编译器隐式地处理析构函数,因为编译器会隐式地给我一个虚拟的,在这种情况下可以做正确的事情。

我再次明确默认了复制构造函数。这纠正了您的版本中忽略复制 Base 的错误。

operator= 看起来就像 Base 版本。

Derived 移动构造函数不需要从 other 移动或复制任何内容,因为它将与 other< 进行交换/.

Derived swap 函数必须交换 Base 部分以及 Derived 部分。


现在考虑使用复制/交换习语。这可能出奇地容易,并且在某些情况下,性能更高。

对于 Base,您可以对所有 5 个特殊成员使用 = default:

class Base
{
int m_i;
public:
virtual ~Base() = default;
Base(const Base&) = default;
Base& operator=(const Base&) = default;
Base(Base&&) = default;
Base& operator=(Base&&) = default;

explicit Base(int i) noexcept
: m_i{i}
{}

friend void swap(Base& a, Base& b) noexcept
{
using std::swap;
swap(a.m_i, b.m_i);
}
};

这里真正需要的唯一工作是自定义构造函数和 swap 函数。

Derived 更简单:

class Derived
: public Base
{
int m_j;
public:
explicit Derived(int j) noexcept
: Base(42)
, m_j{j}
{}

friend void swap(Derived& a, Derived& b) noexcept
{
using std::swap;
swap(static_cast<Base&>(a), static_cast<Base&>(b));
swap(a.m_j, b.m_j);
}
};

所有 5 个特殊成员都可以隐式默认!

我们不能在 Base 中默认它们,因为我们需要指定虚拟析构函数,它禁止生成移动成员,并且用户不推荐生成复制成员-声明的析构函数。但由于我们不需要在 Derived 中声明析构函数,我们可以让编译器处理一切。

由于复制/交换的一大卖点是减少编码,具有讽刺意味的是,使用它实际上需要比让编译器默认特殊成员更多的编码。

当然,如果默认设置不正确,则不要使用它们。我只是说默认值应该是您的第一选择,而不是复制/交换。

关于c++ - 在基类和派生类中 copy-and-swap ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25973103/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com