删除复制构造器& operator =类范围访问

时间:2018-01-23 23:37:12

标签: c++ copy-constructor

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

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被宣布为public

4 个答案:

答案 0 :(得分:5)

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;
};

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

答案 1 :(得分:2)

不,没关系。删除的构造函数只会在重载决策选择后导致编译失败。这意味着如果您删除了私有构造函数,然后尝试在类之外使用,那么在获得删除的构造函数错误之前,您将获得访问错误。

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

答案 2 :(得分:1)

无关紧要有两个原因:

首先,delete避免隐式生成复制构造函数,因此根本不会生成复制构造函数,也不会生成私有,公共或任何部分。

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

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

答案 3 :(得分:1)

就类的使用方式而言,它没有任何区别。

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

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