复制控件似乎与默认构造函数,复制构造函数,复制赋值运算符,析构函数等相关,是用户编写的复制和复合的复制,加上移动复制/赋值。
听起来很复杂。我发现很难记住合成的内容和时间。
只是想知道,如果我不在构造函数或赋值运算符中使用move,我还需要关注差异吗?
答案 0 :(得分:3)
在用户代码中,您几乎不需要编写析构函数,因此复制/移动构造函数和赋值运算符。这是因为您将编写启用RAII的对象类。
我们需要编写析构函数的唯一一次是我们是否控制非RAII资源,例如从c样式或原始c ++库导出的文件句柄或数据库连接。
在这种情况下,我们只需将资源包装在unique_ptr(使用自定义删除工具)或shared_ptr(再次使用自定义删除工具)中,我们就完成了。
这给我们留下了两个场景:
多态接口的基类(不受shared_ptr控制) - 在这种情况下,我们必须编写一个虚拟析构函数,然后根据默认实现实现移动/复制。
一个可移动的类(因为它拥有unique_ptr,比方说?),我们希望它是可复制的。现在我们被迫实施复制操作并默认移动操作。
还有一些其他极端情况,例如您的类是否拥有互斥锁,这是不可复制的。但是,如果您的类拥有互斥锁,则可能已经存在设计错误,要求它可以复制。无论如何,到这个时候你应该已经了解了复制/分配/移动规则。
一些例子:
struct owns_a_file_movable
{
struct file_deleter {
void operator()(FILE* f) const noexcept {
fclose(f);
}
};
// RAII class now, moveable. Copy would not make sense.
std::unique_ptr<FILE, file_deleter> file_;
};
struct owns_a_file_copyable
{
struct file_deleter {
void operator()(FILE* f) const noexcept {
fclose(f);
}
};
// construct from string
owns_a_file_copyable(std::string fname)
: path_(std::move(fname))
, file_(fopen(path_, "r"), file_deleter())
{
}
// we want it to be copyable. In our case, a copy will open another
// instance of the file. so we must store the filename.
owns_a_file_copyable(owns_a_file_copyable const& r)
: path_(t.path_)
, file_(fopen(path_, "r"), file_deleter())
{}
owns_a_file_copyable& operator=(owns_a_file_copyable const& r)
{
auto tmp = r;
std::swap(path_, tmp.path_); // changed: was r.path_ which was wrong
std::swap(file_, tmp.file_);
return *this;
}
owns_a_file_copyable(owns_a_file_copyable&&) = default;
owns_a_file_copyable& operator=(owns_a_file_copyable&&) = default;
// std::string is fully RAII
std::string path_;
// RAII class now, moveable
std::unique_ptr<FILE, file_deleter> file_;
};
struct how_most_classes_should_be
{
// no destructors, copy operators, assignment or move - it's all
// generated for you.
std::string this_;
std::string that_;
std::shared_ptr<const OtherThing> shared_other_; // note - shared semantics
std::function<void()> closure_; // these are copyable too
};
什么触发了什么?
// ordinary constructor
auto y = owns_a_file_copyable("/users/rhodges/foo.txt");
// copy constructor: owns_a_file_copyable(owns_a_file_copyable const&)
auto x = y;
// copy assignment: owns_a_file_copyable& operator-(owns_a_file_copyable const&)
x = y
// move-constructor: owns_a_file_copyable(owns_a_file_copyable &&)
auto z = std::move(x);
// move-assignment: owns_a_file_copyable& operator-(owns_a_file_copyable &&)
z = std::move(y);
// also move-constructor
extern owns_a_file_copyable make_file();
auto w = make_file();
// this time move-assignment
w = make_file();