使用 C++11 中显式删除的成员函数,从不可复制的基类继承是否仍然值得?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9458741/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 12:51:43  来源:igfitidea点击:

With explicitly deleted member functions in C++11, is it still worthwhile to inherit from a noncopyable base class?

c++c++11noncopyable

提问by Emile Cormier

With explicitly deleted member functions in C++11, is it still worthwhile to inherit from a noncopyable base class?

使用 C++11 中显式删除的成员函数,从不可复制的基类继承是否仍然值得?

I'm talking about the trick where you privately inherit a base class which has private or deleted copy constructor and copy assignment (e.g. boost::noncopyable).

我说的是你私下继承一个基类的技巧,该基类具有私有或删除的复制构造函数和复制赋值(例如boost::noncopyable)。

Are the advantages put forward in this questionstill applicable to C++11?

这个问题提出的优点是否仍然适用于C++11?



I don't get why some people claim it's easier to make a class non-copyable in C++11.

我不明白为什么有些人声称在 C++11 中使类不可复制更容易。

In C++03:

在 C++03 中:

private:
    MyClass(const MyClass&) {}
    MyClass& operator=(const MyClass&) {}

In C++11:

在 C++11 中:

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


EDIT:

编辑:

As many people have pointed out, it was a mistake to provide empty bodies (i.e. {}) for the private copy constructor and copy assignment operator, because that would allow the class itself invoke those operators without any errors. I first started out not adding the {}, but ran into some linker issues that made me add the {} for some silly reason (I don't remeber the circumstances). I know better know. :-)

正如许多人指出的那样,为私有复制构造函数和复制赋值运算符提供空体(即 {})是错误的,因为这将允许类本身调用这些运算符而不会出现任何错误。我一开始没有添加 {},但遇到了一些链接器问题,导致我出于某种愚蠢的原因添加了 {}(我不记得当时的情况)。我知道更好。:-)

回答by Nicol Bolas

Well, this:

嗯,这个:

private:
    MyClass(const MyClass&) {}
    MyClass& operator=(const MyClass&) {}

Still technically allows MyClassto be copied by members and friends. Sure, those types and functions are theoretically under your control, but the class is still copyable. At least with boost::noncopyableand = delete, nobodycan copy the class.

技术上仍然允许MyClass成员和朋友复制。当然,这些类型和函数理论上在您的控制之下,但该类仍然是可复制的。至少使用boost::noncopyableand = delete没有人可以复制该类。



I don't get why some people claim it's easier to make a class non-copyable in C++11.

我不明白为什么有些人声称在 C++11 中使类不可复制更容易。

It's not so much "easier" as "more easily digestible".

与其说是“更容易”,不如说是“更容易消化”。

Consider this:

考虑一下:

class MyClass
{
private:
    MyClass(const MyClass&) {}
    MyClass& operator=(const MyClass&) {}
};

If you are a C++ programmer who has read an introductory text on C++, but has little exposure to idiomatic C++ (ie: a lotof C++ programmers), this is... confusing. It declares copy constructors and copy assignment operators, but they're empty. So why declare them at all? Yes, they're private, but that only raises morequestions: why make them private?

如果您是一名 C++ 程序员,并且阅读了有关 C++ 的介绍性文本,但很少接触惯用的 C++(即:很多C++ 程序员),这将是……令人困惑。它声明了复制构造函数和复制赋值运算符,但它们是空的。那么为什么要声明它们呢?是的,它们是private,但这只会引发更多问题:为什么要将它们设为私有?

To understand why this prevents copying, you have to realize that by declaring them private, you make it so that non-members/friends cannot copy it. This is not immediately obvious to the novice. Nor is the error message that they will get when they try to copy it.

要理解为什么这会阻止复制,您必须意识到通过将它们声明为私有,您可以使非成员/朋友无法复制它。这对新手来说并不是很明显。当他们尝试复制它时,也不会出现错误消息。

Now, compare it to the C++11 version:

现在,将其与 C++11 版本进行比较:

class MyClass
{
public:
    MyClass(const MyClass&) = delete;
    MyClass& operator=(const MyClass&) = delete;
};

What does it take to understand that this class cannot be copied? Nothing more than understanding what the = deletesyntax means. Any book explaining the syntax rules of C++11 will tell you exactly what that does. The effect of this code is obvious to the inexperienced C++ user.

怎样才能理解这个类不能被复制?无非是理解= delete语法的含义。任何解释 C++11 语法规则的书都会告诉你它到底做了什么。这段代码的效果对于没有经验的 C++ 用户来说是显而易见的。

What's great about this idiom is that it becomes an idiom because it is the clearest, most obvious way to say exactly what you mean.

这个习语的好处在于它变成了一个习语,因为它是准确表达您的意思的最清晰、最明显的方式。

Even boost::noncopyablerequires a bit more thought. Yes, it's called "noncopyable", so it is self-documenting. But if you've never seen it before, it raises questions. Why are you deriving from something that can't be copied? Why do my error messages talk about boost::noncopyable's copy constructor? Etc. Again, understanding the idiom requires more mental effort.

甚至boost::noncopyable需要多一点思考。是的,它被称为“不可复制”,所以它是自我记录的。但如果你以前从未见过它,它就会提出问题。你为什么要从无法复制的东西中衍生出来?为什么我的错误消息会谈论boost::noncopyable的复制构造函数?等等。同样,理解成语需要更多的脑力劳动。

回答by David Rodríguez - dribeas

The first thing is that as others before me point out, you got the idiom wrong, you declareas private and don't define:

第一件事是,正如我之前的其他人指出的那样,您弄错了习语,您声明为 private 并且没有定义

class noncopyable {
   noncopyable( noncopyable const & );
   noncopyable& operator=( noncopyable const & );
};

Where the return type of the operator=can be basically anything. At this point, if you read that code in a header, what does it actually mean? It can only be copied by friends or it cannot be copied ever? Note that if you provide a definition as in your example, it is stating that I can be copied only inside the class and by friends, it is the lack of a definition what translates this into I cannot be copied. But the lack of a definition in the header is not a synonym for a lack of definition everywhere, as it could be defined in the cpp file.

的返回类型operator=基本上可以是任何东西。此时,如果您在标题中阅读该代码,它实际上意味着什么?它只能被朋友复制还是永远无法复制?请注意,如果您在示例中提供定义,则表明I 只能在课堂内和朋友中被复制,这是由于缺少定义将其翻译为I 不能被复制。但是标题中缺少定义并不是到处都缺少定义的同义词,因为它可以在 cpp 文件中定义。

This is where inheriting from a type called noncopyablemakes it explicit that the intention is to avoid copies, in the same way that if you manually wrote the code above you should documentwith a comment in the line that the intention is disabling copies.

这是继承了一种称为不可复制使得它明确这样做的目的是为了避免拷贝,以同样的方式,如果您手动写上面的代码,你应该记录在这样做的目的是禁止拷贝该行的注释。

C++11 does not change any of this, it just makes the documentation explicit in the code. In the same line that you declare the copy constructor as deleted you are documented that you want it fully disabled.

C++11 不会改变这些,它只是在代码中明确说明文档。在您将复制构造函数声明为已删除的同一行中,您记录了您希望将其完全禁用

As a last comment, the feature in C++11 is not just about being able to write noncopyablewith less code or better, but rather about inhibiting the compiler from generating code that you don't want generated. This is just one use of that feature.

作为最后的评论,C++11 中的特性不仅仅是能够用更少或更好的代码编写不可复制的代码,而是禁止编译器生成您不想生成的代码。这只是该功能的一种用途。

回答by David Stone

In addition to the points others have brought up...

除了其他人提出的要点......

Having a private copy constructor and copy assignment operator that you do not define prevents anyone from making copies. However, if a member function or friend function attempts to make a copy, they will receive a link-time error. If they attempt to do so where you have explicitly deleted those functions, they will receive a compile-time error.

拥有未定义的私有复制构造函数和复制赋值运算符可防止任何人进行复制。但是,如果成员函数或友元函数尝试进行复制,它们将收到链接时错误。如果他们试图在您明确删除这些函数的地方这样做,他们将收到编译时错误。

I always make my errors occur as soon as possible. Make run-time errors happen at the point of error instead of later on (so make the error happen when you change the variable instead of when you read it). Make all run-time errors into link-time errors so the code never has a chance to be wrong. Make all link-time errors into compile-time errors to speed up development and have slightly more useful error messages.

我总是让我的错误尽快发生。使运行时错误发生在错误点而不是稍后(因此在更改变量而不是读取变量时发生错误)。将所有运行时错误转化为链接时错误,这样代码就不会出错。将所有链接时错误转化为编译时错误以加快开发速度并提供更有用的错误消息。

回答by Collin Dauphinee

It's more readable and allows the compiler to give better errors.

它更具可读性,并允许编译器给出更好的错误。

The 'deleted' is more clear to a reader, especially if they're skimming over the class. Likewise, the compiler can tell you that you're trying to copy a non-copyable type, instead of giving you a generic 'trying to access private member' error.

“已删除”对读者来说更清楚,尤其是当他们浏览课程时。同样,编译器可以告诉您您正在尝试复制不可复制的类型,而不是给您一个通用的“尝试访问私有成员”错误。

But really, it's just a convenience feature.

但实际上,这只是一个方便的功能。

回答by ThreeBit

People here are recommending that you declare member functions without defining them. I would like to point out that such an approach isn't portable. Some compilers/linkers require that if you declare a member function then you must also define it, even if it isn't used. If you are using only VC++, GCC, clang then you can get away with this, but if you are trying to write truly portable code then some other compilers (e.g. Green Hills) will fail.

这里的人建议您声明成员函数而不定义它们。我想指出这种方法是不可移植的。一些编译器/链接器要求,如果您声明了一个成员函数,那么您还必须定义它,即使它没有被使用。如果您只使用 VC++、GCC、clang,那么您可以摆脱这种情况,但如果您尝试编写真正可移植的代码,那么其他一些编译器(例如 Green Hills)将失败。