自定义先决条件对移动分配运算符有效吗

Are custom preconditions valid for a move assignment operator?

本文关键字:运算符 有效 分配 移动 先决条件 自定义      更新时间:2023-10-16

在移动分配运算符中对移动目标的状态设置自定义先决条件是否有效?特别是,只允许移动到以前未完全初始化的对象是否有效?

考虑:

struct Foo {
private:
std::unique_ptr<int> value;
public:
Foo(std::unique_ptr<int> value) : value{std::move(value)} {}
Foo(Foo&&) noexcept = default;
Foo &operator =(Foo&& other) noexcept {
assert(!value);
value = std::move(other.value);
return *this;
}
};

例如,我想知道这个类是否可以在不影响断言的情况下与容器一起使用。例如,如果您这样做:

std::vector<Foo> foo;
foo.emplace_back(std::make_unique<int>(42));
foo.emplace_back(std::make_unique<int>(17));
Foo removed = std::move(foo[0]);
foo.erase(foo.begin());

这是否保证与类一起工作,还是依赖于std::vector的实现细节?

在移动分配运算符中对移动目标的状态设置自定义先决条件有效吗?

是的,但是。。。

特别是,只允许移动到以前未完全初始化的对象是否有效?

当然,但是。。。

考虑:

到目前为止没有问题,但是。。。

std::vector<Foo> foo;
// ...

你可以对你的类做任何你想做的事情,直到你将它与std代码(或其他人的代码(一起使用,这会对你的类型提出要求。

例如,标准中关于vector::erase:

对于vectordequeTCpp17MoveAssignable

此处定义了Cpp17MoveAssignable

t = rv

rv的状态未指定。[注意:无论trv是否引用同一对象,rv都必须满足正在使用它的库组件的要求。无论rv是否已从中移动,这些要求中列出的操作都必须按指定操作。--结束注意]

Foo未完全满足Cpp17MoveAssignable要求。只要您不希望Foo使用需要Cpp17MoveAssignable的代码,这就没问题。

免责声明:未来的标准可能会放宽对vector::erase的要求,以允许Foo。但今天的情况并非如此。

请注意,std::remove_if需要Cpp17MoveAssignable:

http://eel.is/c++草稿/算法删除#2

这个对你的程序的轻微修改实际上会断言:

#include <algorithm>
#include <cassert>
#include <memory>
#include <vector>
struct Foo {
private:
std::unique_ptr<int> value;
public:
Foo(std::unique_ptr<int> value) : value{std::move(value)} {}
Foo(Foo&&) noexcept = default;
Foo &operator =(Foo&& other) noexcept {
assert(!value);
value = std::move(other.value);
return *this;
}
bool operator==(int i) const {return *value == i;}
};
int
main()
{
std::vector<Foo> foo;
foo.push_back(std::make_unique<int>(1));
foo.push_back(std::make_unique<int>(2));
foo.push_back(std::make_unique<int>(3));
std::remove_if(foo.begin(), foo.end(),
[](auto const& f) {return f == 1;});
}