【发布时间】:2014-03-13 04:41:26
【问题描述】:
我认为下面的代码比copy-and-swap 习惯用法更好。
这样,你可以使用两个宏来封装复制和移动赋值运算符的定义。换句话说,您可以避免在代码中显式定义它们。因此,您可以只将注意力集中在 ctors 和 dtor 上。
这种方法有什么缺点吗?
class A
{
public:
A() noexcept
: _buf(new char[128])
{}
~A() noexcept
{
if (_buf)
{
delete[] _buf;
_buf = nullptr;
}
}
A(const A& other) noexcept
: A()
{
for (int i = 0; i < 128; ++i)
{
_buf[i] = other._buf[i];
}
}
A(A&& other) noexcept
: _buf(other._buf)
{
_buf = nullptr;
}
A& operator =(const A& other) noexcept
{
if (this != &other)
{
this->~A();
new(this) A(other);
}
return *this;
}
A& operator =(A&& other) noexcept
{
if (this != &other)
{
this->~A();
new(this) A(static_cast<A&&>(other));
}
return *this;
}
private:
char* _buf;
};
【问题讨论】:
-
你的默认构造函数
noexcept到底是怎样的?而且您的移动构造函数不会移动任何东西。在delete之前,无需检查nullptr。为什么static_cast<A&&>而不是std::move? -
_buf(other._buf) and other._buf = nullptr;只是移动操作。
-
如果复制或移动构造函数可以抛出异常,你就有麻烦了。
-
如果你真的写了
other._buf = nullptr;,它应该是移动操作。正如 Kerrek 上面评论的那样,您的两个赋值运算符都没有提供强大的异常保证,而复制和交换可以。 -
@Praetorian
noexcept并不意味着“此函数中的任何内容都不会引发异常”。这意味着“这个函数永远不会发出异常”。noexcept保证是函数接口的特征,很像返回类型。值得注意的是,这不是对该功能如何实现的限制。我在争论语义,我知道你个人理解这一点。但我觉得向那些认为noexcept是编译器针对const之类的实现进行验证的程序员明确区分是很重要的。
标签: c++ design-patterns c++11 constructor idioms