删除复制构造函数 & operator= class 范围访问

Deleting Copy Constructors & operator= class scope access

在旧版本的 C++ 中,如果想要阻止 class 对象的 copying,他们通常会在对象的私有部分中声明 Copy Constructoroperator=() class 这样的:

class Foo {
public:
    Foo(){} // Default
    ~Foo(){} // Default

private:
    Foo( const Foo& c ); // not implemented
    Foo& operator=( const Foo& c ); // not implemented
};

这很简单。现在有了更新版本的 C++,我们现在可以改为执行此操作。

class Foo {
public:
    Foo() = default;
    ~Foo() = default;
private:
    Foo( const Foo& c ) = delete;
    Foo& operator=( const Foo& c ) = delete;
};

然后我的问题变成了:使用将这些声明为 deleted 函数的现代方法,如果在它 class?


比如上面那个和这个有什么区别吗:

class Foo {
public:
    Foo() = default;
    ~Foo() = default;
    Foo( const Foo& c ) = delete;
    Foo& operator=( const Foo& c ) = delete;
};

编辑:

我接受了 ShadowRanger 的回答,因为他们用示例进行了解释,并为此 Q/A 提供了 link,清楚地解释了建议和原因...

我注意到,在第一个示例中,当它们被声明时 private 您将在已经生成的已经存在的 compiler errors 之上获得额外的 compiler errors当它们被声明为 public 时。

不,没关系。删除的构造函数只有在被重载决策选中后才会导致编译失败。这意味着如果您删除了私有构造函数,然后您将尝试在 class 之外使用这些构造函数,您会在收到已删除的构造函数错误之前收到访问错误。

无论哪种方式,无论删除的构造函数在什么范围内,对其的任何调用都将以编译错误结束。

没关系,原因有二:

首先,delete 避免隐式生成复制构造函数,因此根本不会生成复制构造函数,无论是在私有部分还是在 public 或任何部分。

其次,如果 T 具有无法复制的直接或虚拟基 class(已删除、不可访问或不明确),则 class T 的隐式声明或默认复制构造函数被定义为已删除复制构造函数);

所以一个deleted复制构造函数就像没有复制构造函数一样简单,并且由于上面的定义,这不能在子classes中是"repaired"。

It has been recommended that the deleted function be public 如果只是为了简化错误消息。例如,在 gcc 上,当声明已删除的复制构造函数 private 时,错误消息更加冗长,而实际上并没有提供更多信息,例如在 g++ 7 上,无论哪种方式,您都会收到此错误:

deleted_copy.cpp:5:10: error: use of deleted function ‘A::A(const A&)’
    A b = a;
          ^
In file included from deleted_copy.cpp:1:0:
deleted_copy.h:6:5: note: declared here
     A(const A&) = delete;
     ^

但是如果复制构造函数是private,你还会得到(上面给出的错误;关于复制构造函数被删除的错误是最后一个):

deleted_copy.cpp: In function ‘int main()’:
deleted_copy.cpp:5:10: error: ‘A::A(const A&)’ is private within this context
    A b = a;
          ^
In file included from deleted_copy.cpp:1:0:
deleted_copy.h:6:5: note: declared private here
     A(const A&) = delete;
     ^

在这两种情况下,deleted_copy.cpp 是:

#include "deleted_copy.h"

int main() {
   A a;
   A b = a;
}

我的 deleted_copy.h 是:

class A
{
public:
    A() = default;
private:
    A(const A&) = delete;
};

在测试 public 的行为时注释掉 private 行。

class能不能用都一样

但它可以对编译器诊断消息产生影响。使用 g++ 5.4.0 版时,在尝试使用既私有又已删除的成员时,我遇到了有关访问私有成员的编译器错误和有关使用已删除函数的错误。另一方面,几个不同的 clang++ 版本似乎足够聪明,可以只显示有关函数被删除的消息,而忽略不太相关的私有访问细节。

所以我更愿意将这些成员声明为public。函数被删除的事实确实是您想要在无效使用中显示的内容,如果编译器也抱怨私有访问,那只是额外的噪音。而且,也许更重要的是,class 不可复制 and/or 可复制分配的事实是 class 的键 属性 并且可能与人类相关只阅读 public: 部分。