我应该选择指针还是引用作为数据成员?

发布于 2024-07-22 03:36:47 字数 602 浏览 7 评论 0 原文

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

class A {};

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

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

所以B负责更新C的一部分。 我通过 lint 运行了代码,它抱怨引用成员:lint#1725。 这讨论了如何处理默认复制和赋值,这很公平,但是默认复制和赋值对于指针来说也很糟糕,因此几乎没有什么优势。

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

当指针可能为空或可能更改时,我通常只会使用指针作为数据成员。 对于数据成员,还有其他原因更喜欢使用指针而不是引用吗?

由于引用一旦初始化就不应更改,因此包含引用的对象不应该是可分配的,这是真的吗?

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.

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 std::auto_ptr as a data member of the class that owns the pointer, and pass the object around as a reference.

I would generally only use a pointer as a data member 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 initialized?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

玻璃人 2024-07-29 03:36:47

我自己的经验法则:

  • 当您希望对象的生命周期依赖于其他对象的生命周期时,请使用引用成员:这是一种明确的方式来表明您不允许该对象在没有另一个类的有效实例的情况下仍然存在 - 因为没有赋值并且有义务通过构造函数获取引用初始化。 这是设计类的好方法,无需假设其实例是否属于另一个类的成员。您只需假设它们的生命直接与其他实例相关。 它允许您稍后更改使用类实例的方式(使用 new、作为本地实例、作为类成员、由管理器中的内存池生成等)
  • 在其他情况下使用指针 :当您希望稍后更改成员时,请使用指针或 const 指针以确保只读取所指向的实例。 如果该类型应该是可复制的,那么您无论如何都不能使用引用。有时您还需要在特殊函数调用(例如 init() )之后初始化该成员,然后您别无选择,只能使用指针。 但是:在所有成员函数中使用断言来快速检测错误的指针状态!
  • 如果您希望对象生存期依赖于外部对象的生存期,并且您还需要该类型可复制,然后使用指针成员但在构造函数中引用参数 这样,您就可以在构造中指示该对象的生命周期取决于参数的生命周期,但实现使用指针仍然是可复制的。 只要这些成员仅通过复制进行更改,并且您的类型没有默认构造函数,则该类型应该满足这两个目标。

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 its 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 functions 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 constructor That 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 doesn't have a default constructor, the type should fulfill both goals.
红衣飘飘貌似仙 2024-07-29 03:36:47

避免引用成员,因为它们限制类的实现可以执行的操作(包括,正如您提到的,阻止赋值运算符的实现),并且不会为类可以提供的功能提供任何好处。

示例问题:

  • 您被迫初始化每个构造函数的初始化列表中的引用:无法将此初始化分解到另一个函数中(直到 C++0x,无论如何 编辑: C++ 现在有委托构造函数
  • 引用不能反弹或为空。 这可能是一个优点,但如果代码需要更改以允许重新绑定或成员为空,则成员的所有使用都需要更改,
  • 与指针成员不同,引用不能轻易地被智能指针或迭代器替换为重构可能需要
  • 每当使用引用时,它看起来像值类型(. 运算符等),但行为就像指针(可以悬挂) - 例如 Google 样式指南 不鼓励这样做

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, anyway edit: 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 Guide discourages it
ら栖息 2024-07-29 03:36:47

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

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

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

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

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

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.

|煩躁 2024-07-29 03:36:47

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

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

然而,正如用户 pts 已经评论的那样,对于大多数其他对象来说情况并非如此。 在这里,使用引用成员可能是一个大问题,通常应该避免。

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 valid reference 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::noncopyable or declaring them private).

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.

森林很绿却致人迷途 2024-07-29 03:36:47

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

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

  • 在向函数传递参数时,始终始终使用引用(基本类型除外),或者当算法需要副本时。

    在向

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

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.

迷爱 2024-07-29 03:36:47

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

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

  • 永远不要使用引用,因为 它会阻止赋值
  • 如果你的类负责删除,
  • ,使用 boost 的scoped_ptr(比 auto_ptr 更安全) ,否则,使用指针或 const 指针

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?

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
淡紫姑娘! 2024-07-29 03:36:47

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

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

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.

花开半夏魅人心 2024-07-29 03:36:47

我建议不要引用数据成员,因为您永远不知道谁将从您的类中派生以及他们可能想要做什么。 他们可能不想使用引用的对象,但作为引用,您迫使他们提供有效的对象。
我已经对自己做了足够多的事情以停止使用参考数据成员。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文