C++ 我应该更喜欢成员数据中的指针还是引用?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/892133/
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 17:48:47  来源:igfitidea点击:

Should I prefer pointers or references in member data?

c++referenceclass-members

提问by markh44

This is a simplified example to illustrate the question:

这是一个简单的例子来说明这个问题:

class A {};

class B
{
    B(A& a) : a(a) {}
    A& a;
};

class C
{
    C() : b(a) {} 
    A a;
    B b; 
};

So B is responsible for updating a part of C. I ran the code through lint and it whinged about the reference member: lint#1725. This talks about taking care over default copy and assignments which is fair enough, but default copy and assignment is also bad with pointers, so there's little advantage there.

所以 B 负责更新 C 的一部分。我通过 lint 运行代码,它抱怨引用成员:lint#1725。这谈到照顾默认复制和分配是足够公平的,但是默认复制和分配对于指针也很糟糕,所以那里几乎没有优势。

I always try to use references where I can since naked pointers introduce uncertaintly about who is responsible for deleting that pointer. I prefer to embed objects by value but if I need a pointer, I use auto_ptr in the member data of the class that owns the pointer, and pass the object around as a reference.

我总是尽量使用引用,因为裸指针不确定地引入了谁负责删除该指针。我更喜欢按值嵌入对象,但如果我需要一个指针,我会在拥有该指针的类的成员数据中使用 auto_ptr,并将该对象作为引用传递。

I would generally only use a pointer in member data when the pointer could be null or could change. Are there any other reasons to prefer pointers over references for data members?

当指针可能为空或可能更改时,我通常只会在成员数据中使用指针。是否有任何其他原因更喜欢指针而不是数据成员的引用?

Is it true to say that an object containing a reference should not be assignable, since a reference should not be changed once initialised?

是否可以说包含引用的对象不应该是可赋值的,因为一旦初始化就不应更改引用?

采纳答案by James Hopkin

Avoid reference members, because they restrict what the implementation of a class can do (including, as you mention, preventing the implementation of an assignment operator) and provide no benefits to what the class can provide.

避免引用成员,因为它们限制了类的实现可以做什么(包括,正如你提到的,阻止赋值运算符的实现)并且没有为类可以提供的东西提供任何好处。

Example problems:

示例问题:

  • you are forced to initialise the reference in each constructor's initialiser list: there's no way to factor out this initialisation into another function (until C++0x, anywayedit:C++ now has delegating constructors)
  • the reference cannot be rebound or be null. This can be an advantage, but if the code ever needs changing to allow rebinding or for the member to be null, all uses of the member need to change
  • unlike pointer members, references can't easily be replaced by smart pointers or iterators as refactoring might require
  • Whenever a reference is used it looks like value type (.operator etc), but behaves like a pointer (can dangle) - so e.g. Google Style Guidediscourages it
  • 您被迫在每个构造函数的初始化列表中初始化引用:无法将此初始化分解为另一个函数(直到 C++0x,无论如何编辑:C++ 现在具有委托构造函数
  • 引用不能被反弹或为空。这可能是一个优势,但如果代码需要更改以允许重新绑定或成员为空,则该成员的所有用途都需要更改
  • 与指针成员不同,引用不能轻易被智能指针或迭代器替换,因为重构可能需要
  • 每当使用引用时,它看起来像值类型(.运算符等),但表现得像指针(可以悬垂)-因此例如Google 样式指南不鼓励它

回答by Klaim

My own rule of thumb :

我自己的经验法则:

  • Use a reference member when you want the life of your object to be dependent on the life of other objects: it's an explicit way to say that you don't allow the object to be alive without a valid instance of another class - because of no assignment and the obligation to get the references initialization via the constructor. It's a good way to design your class without assuming anything about it's instance being member or not of another class.You only assume that their lives are directly linked to other instances. It allows you to change later how you use your class instance (with new, as a local instance, as a class member, generated by a memory pool in a manager, etc.)
  • Use pointer in other cases: When you want the member to be changed later, use a pointer or a const pointer to be sure to only read the pointed instance. If that type is supposed to be copyable, you cannot use references anyway.Sometimes you also need to initialize the member after a special function call ( init() for example) and then you simply have no choice but to use a pointer. BUT : use asserts in all your member function to quickly detect wrong pointer state!
  • In cases where you want the object lifetime to be dependent on an external object's lifetime, and you also need that type to be copyable, then use pointer members but reference argument in constructorThat way you are indicating on construction that the lifetime of this object depends on the argument's lifetime BUT the implementation use pointers to still be copyable. As long as these members are only changed by copy, and your type don't have a default constructor, the type should fullfil both goals.
  • 当您希望对象的生命周期依赖于其他对象的生命周期时,请使用引用成员:这是一种明确的方式,表示您不允许对象在没有另一个类的有效实例的情况下存活 - 因为没有赋值和通过构造函数获取引用初始化的义务。这是一种设计类的好方法,无需假设它的实例是否属于另一个类。您只假设他们的生活与其他实例直接相关。它允许您稍后更改您使用类实例的方式(使用 new、作为本地实例、作为类成员、由管理器中的内存池生成等)
  • 在其他情况下使用指针:当您希望稍后更改成员时,请使用指针或 const 指针以确保仅读取指向的实例。如果该类型应该是可复制的,则无论如何都不能使用引用。有时您还需要在特殊函数调用(例如 init() )之后初始化成员,然后您别无选择,只能使用指针。但是:在所有成员函数中使用断言来快速检测错误的指针状态!
  • 如果您希望对象生命周期依赖于外部对象的生命周期,并且您还需要该类型是可复制的,那么在构造函数中使用指针成员但引用参数这样,您就表明该对象的生命周期取决于构造在参数的生命周期中,但实现使用指针仍然是可复制的。只要这些成员仅通过复制更改,并且您的类型没有默认构造函数,该类型就应该满足这两个目标。

回答by Mykola Golubyev

Objects rarely should allow assign and other stuff like comparison. If you consider some business model with objects like 'Department', 'Employee', 'Director', it is hard to imagine a case when one employee will be assigned to other.

对象很少应该允许分配和其他诸如比较之类的东西。如果您考虑某些具有“部门”、“员工”、“主管”等对象的业务模型,则很难想象将一名员工分配给另一名员工的情况。

So for business objects it is very good to describe one-to-one and one-to-many relationships as references and not pointers.

因此,对于业务对象,将一对一和一对多关系描述为引用而不是指针是非常好的。

And probably it is OK to describe one-or-zero relationship as a pointer.

可能可以将一或零关系描述为指针。

So no 'we can't assign' then factor.
A lot of programmers just get used with pointers and that's why they will find any argument to avoid use of reference.

所以没有'我们不能分配'然后因素。
许多程序员只是习惯于使用指针,这就是为什么他们会找到任何参数来避免使用引用。

Having a pointer as a member will force you or member of your team to check the pointer again and again before use, with "just in case" comment. If a pointer can be zero then pointer probably is used as kind of flag, which is bad, as every object have to play its own role.

将指针作为成员将迫使您或您的团队成员在使用前一次又一次地检查指针,并带有“以防万一”注释。如果指针可以为零,那么指针可能被用作一种标志,这是不好的,因为每个对象都必须发挥自己的作用。

回答by Konrad Rudolph

In a few important cases, assignability is simply not needed. These are often lightweight algorithm wrappers that facilitate calculation without leaving the scope. Such objects are prime candidates for reference members since you can be sure that they always hold a validreference and never need to be copied.

在一些重要的情况下,根本不需要可分配性。这些通常是轻量级算法包装器,可在不离开范围的情况下促进计算。此类对象是引用成员的主要候选对象,因为您可以确保它们始终持有有效引用并且永远不需要复制。

In such cases, make sure to make the assignment operator (and often also the copy constructor) non-usable (by inheriting from boost::noncopyableor declaring them private).

在这种情况下,请确保使赋值运算符(通常还有复制构造函数)不可用(通过继承boost::noncopyable或声明它们为私有)。

However, as user pts already commented, the same is not true for most other objects. Here, using reference members can be a huge problem and should generally be avoided.

但是,正如用户 pts 已经评论过的,大多数其他对象并非如此。在这里,使用引用成员可能是一个大问题,通常应该避免。

回答by Konrad Rudolph

As everyone seems to be handing out general rules, I'll offer two:

由于每个人似乎都在制定一般规则,我将提供两个:

  • Never, ever use use references as class members. I have never done so in my own code (except to prove to myself that I was right in this rule) and cannot imagine a case where I would do so. The semantics are too confusing, and it's really not what references were designed for.

  • Always, always, use references when passing parameters to functions, except for the basic types, or when the algorithm requires a copy.

  • 永远不要使用引用作为类成员。我从来没有在我自己的代码中这样做过(除了向自己证明我在这条规则中是正确的)并且无法想象我会这样做的情况。语义太混乱了,这真的不是引用的设计目的。

  • 在向函数传递参数时,总是,总是使用引用,除了基本类型,或者当算法需要副本时。

These rules are simple, and have stood me in good stead. I leave making rules on using smart pointers (but please, not auto_ptr) as class members to others.

这些规则很简单,对我很有帮助。我留下了关于使用智能指针(但请不要使用 auto_ptr)作为其他人的类成员的规则。

回答by pts

Yes to: Is it true to say that an object containing a reference should not be assignable, since a reference should not be changed once initialised?

Yes to:是否可以说包含引用的对象不应该是可赋值的,因为一旦初始化就不应更改引用?

My rules of thumb for data members:

我对数据成员的经验法则:

  • never use a reference, because it prevents assignment
  • if your class is responsible for deleting, use boost's scoped_ptr (which is safer than an auto_ptr)
  • otherwise, use a pointer or const pointer
  • 永远不要使用引用,因为它会阻止赋值
  • 如果您的班级负责删除,请使用 boost 的 scoped_ptr(比 auto_ptr 更安全)
  • 否则,使用指针或常量指针

回答by StephenD

I advise against reference data members becasue you never know who is going to derive from your class and what they might want to do. They might not want to make use of the referenced object, but being a reference you have forced them to provide a valid object. I've done this to myself enough to stop using reference data members.

我建议不要引用数据成员,因为你永远不知道谁将从你的类中派生出来,以及他们可能想要做什么。他们可能不想使用被引用的对象,但作为一个引用,你已经迫使他们提供一个有效的对象。我已经对自己这样做了,足以停止使用引用数据成员。

回答by Dani van der Meer

I would generally only use a pointer in member data when the pointer could be null or could change. Are there any other reasons to prefer pointers over references for data members?

当指针可能为空或可能更改时,我通常只会在成员数据中使用指针。是否有任何其他原因更喜欢指针而不是数据成员的引用?

Yes. Readability of your code. A pointer makes it more obvious that the member is a reference (ironically :)), and not a contained object, because when you use it you have to de-reference it. I know some people think that is old fashioned, but I still think that it simply prevent confusion and mistakes.

是的。代码的可读性。指针使成员更明显地是引用(具有讽刺意味的是:)),而不是包含的对象,因为当您使用它时,您必须取消引用它。我知道有些人认为这是过时的,但我仍然认为它只是防止混淆和错误。

回答by Kit10

If I understand the question correctly...

如果我正确理解问题...

Reference as function parameter instead of pointer:As you pointed out, a pointer doesn't make it clear who owns the cleanup/initialization of the pointer. Prefer a shared point when you want a pointer, it's a part of C++ 11, and a weak_ptr when the validity of the data is not guaranteed through the lifetime of the class accepting the pointed to data.; also a part of C++ 11. Using a reference as a function parameter guarantees that the reference is not null. You have to subvert the language features to get around this, and we don't care about loose cannon coders.

作为函数参数而不是指针引用:正如您所指出的,指针并不清楚谁拥有指针的清理/初始化。当你想要一个指针时,最好使用共享点,它是 C++ 11 的一部分,当在接受指向数据的类的生命周期中不能保证数据的有效性时,最好使用 weak_ptr。也是 C++ 11 的一部分。使用引用作为函数参数保证引用不为空。你必须颠覆语言特性来解决这个问题,我们不关心松散的大炮编码器。

Reference a a member variable:As as above in regards to data validity. This guaranties the pointed to data, then referenced, is valid.

引用 aa 成员变量:同上关于数据有效性。这保证了指向的数据,然后引用,是有效的。

Moving responsibility of variable validity to an earlier point in the code not only cleans up the later code (the the class A in your example), but also makes it clear to the person using.

将变量有效性的责任移到代码中的较早位置不仅可以清理后面的代码(示例中的 A 类),而且还可以让使用人员清楚地了解。

In your example, which is a bit confusing (I'd really try to find a more clearer implementation), the A used by B is guaranteed for the lifetime of the B, since B is a member of A, so a reference reinforces this and is (perhaps) more clear.

在您的示例中,这有点令人困惑(我真的会尝试找到更清晰的实现),B 使用的 A 在 B 的生命周期内得到保证,因为 B 是 A 的成员,因此引用加强了这一点并且(也许)更清楚。

And just in case (which is a low likely hood as it wouldn't make any sense in your codes context), another alternative, to use a non referenced, non pointer A parameter, would copy A, and make the paradigm useless - I really don't think you mean this as an alternative.

以防万一(这是一个可能性很小的引擎盖,因为它在您的代码上下文中没有任何意义),另一种选择,使用非引用的非指针 A 参数,将复制 A,并使范式无用 - 我真的不认为你的意思是作为替代。

Also, this also guarantees you aren't able to change the data referenced, where a pointer can be modified. A const pointer would work, only if the referenced/pointer to data was not mutable.

此外,这也保证您无法更改引用的数据,其中可以修改指针。只有当引用/指向数据的指针不可变时,const 指针才会起作用。

Pointers are useful if the A parameter for B was not guaranteed to be set, or could be reassigned. And sometimes a weak-pointer is just too verbose for the implementation, and a good number of people either don't know what a weak_ptr is, or just dislike them.

如果不能保证设置 B 的 A 参数或可以重新分配,则指针很有用。有时弱指针对于实现来说太冗长了,很多人要么不知道weak_ptr是什么,要么就是不喜欢它们。

Tear apart this answer, please :)

撕开这个答案,请:)