代码之家  ›  专栏  ›  技术社区  ›  Roger Pate

为什么要“默认”复制/移动构造函数或析构函数?

  •  7
  • Roger Pate  · 技术社区  · 14 年前

    struct A {
      A() = default;          // default ctor
      A(A const&) = default;  // copy ctor
      A(A&&) = default;       // move ctor
      A(Other);               // other ctor
    
      ~A() = default;         // dtor
    
      A& operator=(A const&) = default; // copy assignment
      A& operator=(A&&) = default;      // move assignment
    };
    

    这些函数的实现与编译器生成它们的实现是一样的,在大多数情况下,当您不声明自己的函数时,通常会发生这种情况。

    默认的ctor是

    但是,除非基成员或数据成员排除了它们,否则类总是有一个复制和移动对象,如果排除了它们,则默认实现将不起作用。一个类总是有一个dtor。

    为什么需要显式默认一个复制构造函数、移动构造函数或析构函数?隐式生成的实现不会做同样的事情吗?

    2 回复  |  直到 14 年前
        1
  •  11
  •   Roger Pate Roger Pate    14 年前

    您可能需要这样做来更改它们对非公共的访问,或者控制哪个翻译单元定义它们。

    非公开

    struct A {
    protected:
      ~A();
    
    private:
      A();
      A(A const&);
      A(A&&);
    };
    
    // according to N3092, §8.4.2/2, cannot be non-public and defaulted
    // in the class definition
    A::~A() = default;
    A::A() = default;
    A::A(A const&) = default;
    A::A(A&&) = default;
    

    这个类可以默认构造、复制和移动,但是 这对于工厂来说是很有用的,因为那里的建筑可能会受到更严格的控制。

    受保护的析构函数是 public-virtual/protected-nonvirtual guideline 对于基类:

    定义控制

    另外,默认函数可以用来维护稳定的二进制接口,因为您可以控制默认函数的定义位置。default并不意味着内联,正如隐式声明的版本那样。(在上面的代码中,默认函数不能在头中,也不能添加内联说明符。)

        2
  •  2
  •   Dennis Zickefoose    14 年前

    除了功能性的目的之外,我发现它对于清晰来说很有用。它清楚地表明,该结构是默认可构造的(或其他),并且我们使用的是编译器生成的行为。代码的自文档化越多越好。