语言特性 -- defaulted and deleted functions

学而时习之,不亦说乎


Introduction

众所周知,C++类的特殊成员(构造函数、析构函数和赋值运算符),它们可以由编译器默认实现或由开发人员自己实现。但是,默认实现的规则有点复杂,可能会导致一些问题。 另一方面,我们有时希望防止对象复制、移动甚至构造对象。
这些都可以通过使用特殊的技巧来实现。在C++11的标准中,简化了许多。

类的特殊成员函数

特种成员函数

  • 默认构造函数
  • 析构函数
  • 拷贝构造函数
  • 拷贝赋值运算符
  • 移动构造函数
  • 移动赋值运算符

生成规则

  • 如果存在用户自己的构造函数,则编译器不生成默认构造函数。
  • 如果存在用户自己的虚拟析构函数,则默认情况下不生成默认构造函数。
  • 如果存在用户定义的移动构造函数或移动赋值运算符,则默认情况下不会生成复制构造函数和复制赋值运算符。
    还有其它一些规则,具体这些成员函数的生成规则建议参考<<effective modern c++>>一书条款17

实现机制

  • 需要编译器defalut函数,请使用=default。 只有具有默认值的特殊类成员函数才能使用这一用法,其它普通函数不可
// 类的特殊成员函数
struct Foo {
  Foo() = default;
};
  • 需要删除某个函数,请使用 =delete。 任何函数,包括非成员函数,都可以删除
// 类的特殊成员函数
struct Foo {
  Foo(Foo const&) = delete;
};

// 普通函数
void func(int) = delete;

用途

  • 实现不可复制且隐式不可移动的类,将复制构造函数和复制赋值运算符声明为已删除:
// 类的特殊成员函数
struct foo_not_copyable {
  foo_not_copyable() = default;

  foo_not_copyable(foo_not_copyable const &) = delete;
  foo_not_copyable& operator=(foo_not_copyable const&) = delete;
};
  • 实现不可复制但可移动的类,将复制操作声明为删除并且显式实现移动操作(并提供所需的任何其他构造函数):
struct data_wrapper {
public:
  data_wrapper(Data *d = nullptr) : data(d) {}

  ~data_wrapper() { delete data; }

  data_wrapper(data_wrapper const&) = delete;
  data_wrapper& operator=(data_wrapper const&) = delete;

  data_wrapper(data_wrapper&& other) : data(std::move(other.
      data)) {
    other.data = nullptr;
  }

  data_wrapper& operator=(data_wrapper&& other) {
    if (this != std::addressof(other)) {
      delete data;
      data = std::move(other.data);
      other.data = nullptr;
    }
    return *this;
  }

private:
  Data *data;
};
  • 为确保函数仅使用特定类型形参,需要为函数提供删除的重载
template <typename T>
void run(T val) = delete;

void run(long val) {} // can only be called with long integers
run(42); // error, matches a deleted overload
run(42L); // OK, long integer arguments are allowed

Ref

Effective Modern C++

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容