这是五法则(或四加 1/2 法则)的正确实施吗?
Is this a proper implementation of the Rule of Five (or Rule of Four and 1/2)?
我正在研究五法则及其表兄弟(四法则和 1/2、复制和交换成语、朋友交换功能)。
我在测试中实施了 4 和 1/2 的规则 class。它编译得很好。我的实现有什么隐藏的错误吗?
我特别关注存储在 m_unorederd_map 属性 中的 unique_ptrs ,因为它们可以移动到复制构造函数中'不要被复制。这是在 classes 中处理 unique_ptrs 的正确方法吗?
someclass.h
#ifndef SOMECLASS_H
#define SOMECLASS_H
#include "someotherclass.h"
#include <QString>
#include <QStringList>
#include <memory>
#include <string>
#include <unordered_map>
class SomeClass
{
QString m_qstring;
std::unordered_map<std::string, std::unique_ptr<SomeOtherClass>> m_unordered_map;
int m_int;
std::string m_string;
QStringList m_qstringlist;
public:
SomeClass() = default;
// Rule of 5 (or Rule of 4 and 1/2)
// From
~SomeClass() = default; // Destructor
SomeClass(SomeClass &other); // Copy constructor
SomeClass(SomeClass &&other); // Move constructor
SomeClass &operator=(SomeClass other); // Copy/Move assignment operator
friend void swap(SomeClass &first, SomeClass &second) // Friend swap function
{
using std::swap;
first.m_qstring.swap(second.m_qstring);
first.m_unordered_map.swap(second.m_unordered_map);
swap(first.m_int, second.m_int);
swap(first.m_string, second.m_string);
first.m_qstringlist.swap(second.m_qstringlist);
}
};
#endif // SOMECLASS_H
someclass.cpp
#include "someclass.h"
// Copy constructor
SomeClass::SomeClass(SomeClass &other)
: m_qstring(other.m_qstring),
m_int(other.m_int),
m_string(other.m_string),
m_qstringlist(other.m_qstringlist)
{
// m_unordered_map holds unique_ptrs which can't be copied.
// So we move it.
m_unordered_map = std::move(other.m_unordered_map);
}
// Move constructor
SomeClass::SomeClass(SomeClass &&other)
: SomeClass()
{
swap(*this, other);
}
// Copy/Move assignment operator
SomeClass &SomeClass::operator=(SomeClass other)
{
swap(*this, other);
return *this;
}
最重要的是:
- 此 class 不需要自定义 copy/move 操作或析构函数,因此应遵循规则 0。
其他:
我不喜欢移动构造函数中的 swap(*this, other);
。它强制成员 default-constructed 然后分配。更好的选择是使用成员初始化列表,其中 std::exchange
.
如果初始化所有成员变得乏味,请将它们包装在一个结构中。它也使编写 swap
更容易。
复制构造函数必须通过 const 引用获取参数。
unique_ptrs which can't be copied. So we move it.
是一个糟糕的理由。如果您的成员无法被复制,请不要定义复制操作。存在自定义移动操作时,不会自动生成复制操作
移动操作(包括 by-value 赋值)应该是 noexcept
,因为标准容器在某些情况下不会使用它们。
SomeClass() = default;
导致通常未初始化的成员 (int m_int;
) 有时会被置零,具体取决于 class 的构造方式。 (例如 SomeClass x{};
将其归零,但 SomeClass x;
不会。)
除非你想要这种行为,否则构造函数应该替换为SomeClass() {}
,并且m_int
可能应该归零(在class正文)。
我正在研究五法则及其表兄弟(四法则和 1/2、复制和交换成语、朋友交换功能)。
我在测试中实施了 4 和 1/2 的规则 class。它编译得很好。我的实现有什么隐藏的错误吗?
我特别关注存储在 m_unorederd_map 属性 中的 unique_ptrs ,因为它们可以移动到复制构造函数中'不要被复制。这是在 classes 中处理 unique_ptrs 的正确方法吗?
someclass.h
#ifndef SOMECLASS_H
#define SOMECLASS_H
#include "someotherclass.h"
#include <QString>
#include <QStringList>
#include <memory>
#include <string>
#include <unordered_map>
class SomeClass
{
QString m_qstring;
std::unordered_map<std::string, std::unique_ptr<SomeOtherClass>> m_unordered_map;
int m_int;
std::string m_string;
QStringList m_qstringlist;
public:
SomeClass() = default;
// Rule of 5 (or Rule of 4 and 1/2)
// From
~SomeClass() = default; // Destructor
SomeClass(SomeClass &other); // Copy constructor
SomeClass(SomeClass &&other); // Move constructor
SomeClass &operator=(SomeClass other); // Copy/Move assignment operator
friend void swap(SomeClass &first, SomeClass &second) // Friend swap function
{
using std::swap;
first.m_qstring.swap(second.m_qstring);
first.m_unordered_map.swap(second.m_unordered_map);
swap(first.m_int, second.m_int);
swap(first.m_string, second.m_string);
first.m_qstringlist.swap(second.m_qstringlist);
}
};
#endif // SOMECLASS_H
someclass.cpp
#include "someclass.h"
// Copy constructor
SomeClass::SomeClass(SomeClass &other)
: m_qstring(other.m_qstring),
m_int(other.m_int),
m_string(other.m_string),
m_qstringlist(other.m_qstringlist)
{
// m_unordered_map holds unique_ptrs which can't be copied.
// So we move it.
m_unordered_map = std::move(other.m_unordered_map);
}
// Move constructor
SomeClass::SomeClass(SomeClass &&other)
: SomeClass()
{
swap(*this, other);
}
// Copy/Move assignment operator
SomeClass &SomeClass::operator=(SomeClass other)
{
swap(*this, other);
return *this;
}
最重要的是:
- 此 class 不需要自定义 copy/move 操作或析构函数,因此应遵循规则 0。
其他:
我不喜欢移动构造函数中的
swap(*this, other);
。它强制成员 default-constructed 然后分配。更好的选择是使用成员初始化列表,其中std::exchange
.如果初始化所有成员变得乏味,请将它们包装在一个结构中。它也使编写
swap
更容易。复制构造函数必须通过 const 引用获取参数。
unique_ptrs which can't be copied. So we move it.
是一个糟糕的理由。如果您的成员无法被复制,请不要定义复制操作。存在自定义移动操作时,不会自动生成复制操作移动操作(包括 by-value 赋值)应该是
noexcept
,因为标准容器在某些情况下不会使用它们。SomeClass() = default;
导致通常未初始化的成员 (int m_int;
) 有时会被置零,具体取决于 class 的构造方式。 (例如SomeClass x{};
将其归零,但SomeClass x;
不会。)除非你想要这种行为,否则构造函数应该替换为
SomeClass() {}
,并且m_int
可能应该归零(在class正文)。