Ðаn*_*Ðаn 2 c++ unique-ptr move-semantics c++11
编辑:制作Foo并Bar稍微不那么琐碎,直接替换shared_ptr<>更难.
应该unique_ptr<>用作实现移动语义的更简单方法吗?
对于像这样的课程
class Foo
{
int* m_pInts;
bool usedNew;
// other members ...
public:
Foo(size_t num, bool useNew=true) : usedNew(useNew) {
if (usedNew)
m_pInts = new int[num];
else
m_pInts = static_cast<int*>(calloc(num, sizeof(int)));
}
~Foo() {
if (usedNew)
delete[] m_pInts;
else
free(m_pInts);
}
// no copy, but move
Foo(const Foo&) = delete;
Foo& operator=(const Foo&) = delete;
Foo(Foo&& other) {
*this = std::move(other);
}
Foo& operator=(Foo&& other) {
m_pInts = other.m_pInts;
other.m_pInts = nullptr;
usedNew = other.usedNew;
return *this;
}
};
Run Code Online (Sandbox Code Playgroud)
随着数据成员的添加,实施移动变得更加繁琐.但是,可移动数据可以放在一个单独的struct,其实例由其管理unique_ptr<>.这允许=default用于移动:
class Bar
{
struct Data
{
int* m_pInts;
bool usedNew;
// other members ...
};
std::unique_ptr<Data> m_pData = std::make_unique<Data>();
public:
Bar(size_t num, bool useNew = true) {
m_pData->usedNew = useNew;
if (m_pData->usedNew)
m_pData->usedNew = new int[num];
else
m_pData->m_pInts = static_cast<int*>(calloc(num, sizeof(int)));
}
~Bar() {
if (m_pData->usedNew)
delete[] m_pData->m_pInts;
else
free(m_pData->m_pInts);
}
// no copy, but move
Bar(const Bar&) = delete;
Bar& operator=(const Bar&) = delete;
Bar(Bar&& other) = default;
Bar& operator=(Bar&& other) = default;
};
Run Code Online (Sandbox Code Playgroud)
除了unique_ptr<>实例的内存总是在堆上之外,这样的实现还存在哪些其他问题?
是.您正在寻找的是零规则(作为三/五规则的C++ 11扩展).通过让您的数据都知道如何复制和移动自己,外部类不需要编写任何特殊的成员函数.编写这些特殊成员可能容易出错,因此不必编写它们就可以解决很多问题.
所以Foo会成为:
class Foo
{
std::unique_ptr<size_t[]> data;
public:
Foo(size_t size): data(new size_t[size]) { }
};
Run Code Online (Sandbox Code Playgroud)
这很容易证明正确性.
这就是所谓的“零法则”。
零规则规定大多数类不实现复制/移动分配/构造或销毁。相反,您将其委托给资源处理类。
5 条规则规定,如果您实现 5 个复制/移动分配/ctor 或 dtor 中的任何一个,您应该实现或删除所有 5 个(或者,经过适当考虑后,默认它们)。
在您的情况下,m_pInts应该是一个唯一的指针,而不是原始内存处理的缓冲区。如果它与某些东西(例如大小)相关,那么您应该编写一个实现 5 规则的指针和大小结构。或者,std::vector<int>如果 3 个指针而不是 2 个指针的开销是可以接受的,则只需使用 a 。
其中一部分是您停止new直接调用。 new是直接管理资源的 5 规则类型中的实现细节。业务逻辑类不要搞乱new。它们既不新建,也不删除。
unique_ptr只是资源管理类型中的一种。 std::string, std::vector, std::set, shared_ptr, std::future, std::function-- 大多数 C++std类型都符合条件。自己编写也是一个好主意。但是当你这样做时,你应该从“业务逻辑”中剥离资源代码。
因此,如果您编写了一个std::function<R(Args...)>克隆,您可以使用 aunique_ptr或 aboost::value_ptr来存储函数对象的内部内容。也许您甚至会编写sbo_value_ptr有时存在于堆上、有时存在于本地的 a 。
然后你可以用“业务逻辑”来包装它,它std::function理解所指向的东西是可调用的等等。
“业务逻辑”std::function不会实现复制/移动分配/构造函数,也不会实现析构函数。他们可能会=default明确表示。
| 归档时间: |
|
| 查看次数: |
402 次 |
| 最近记录: |