【问题标题】:Deleting Copy Constructors & operator= class scope access删除复制构造函数 & operator= 类范围访问
【发布时间】:2018-01-23 23:37:11
【问题描述】:

在旧版本的 C++ 中,如果想要阻止类对象的 copying,他们通常会在类的私有部分中声明 Copy Constructor 和 operator=(),如下所示:

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 Foo {
public:
    Foo() = default;
    ~Foo() = default;
    Foo( const Foo& c ) = delete;
    Foo& operator=( const Foo& c ) = delete;
};

编辑:

我接受了 ShadowRanger 的回答,因为他们通过示例进行了解释,并提供了指向此 Q/A 的链接,该链接清楚地解释了建议及其原因...

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

【问题讨论】:

  • 不是真的 imo 。
  • 我认为没有;只是想澄清一下。我不想假设并且想要在设计类时编译器如何处理它的观点。

标签: c++ copy-constructor


【解决方案1】:

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 行注释掉。

【讨论】:

  • 感谢您提供示例的澄清答案。我通常不使用 clang 或 gcc;主要使用visual studio,但是知道它很好。
  • 我也搜索了一个类似问题的堆栈,但直到您在答案顶部提供了一个链接后才找到任何问题,谢谢您的链接。
  • 好吧,我发现在进行搜索时,我缺少删除关键字的术语 modifier。在阅读了您提供的链接中的问答后,回答了与compiler 和linker 相关的其他类似问题,但仍然符合关于声明它们public 或private 之间区别的问题。由于更好地了解建议的内容,我将不得不接受您的回答而不是其他人。
【解决方案2】:

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

无论哪种方式,无论被删除的构造函数的作用域是什么,对它的任何调用都会以编译错误结束。

【讨论】:

  • 感谢您的快速回答,我认为没有,但不喜欢假设只是想澄清一下。在设计具有compiler 如何对待它的角度的类时,它更倾向于。
【解决方案3】:

没关系,有两个原因:

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

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

所以deleted 复制构造函数就像没有复制构造函数一样,并且由于上述定义,这不能在子类中“修复”。

【讨论】:

  • “根本没有生成复制构造函数” - 差不多。它仍然存在,只是没有为其生成任何正文代码。但是重载决议等仍然可以找到deleted 复制构造函数,如果没有其他候选者,它只会发出错误。
【解决方案4】:

类的使用与否没有区别。

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

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

【讨论】:

    猜你喜欢
    • 2021-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-19
    • 1970-01-01
    • 2018-06-03
    • 2011-04-08
    相关资源
    最近更新 更多