取消引用指针来获取引用是错误的吗?
我更喜欢在任何地方都使用引用,但是当您使用 STL 容器时,您必须使用指针,除非您确实想按值传递复杂类型。我觉得转换回参考很肮脏,这似乎是错误的。
是吗?
澄清一下......
MyType *pObj = ...
MyType &obj = *pObj;
这不是“脏”吗,因为你可以(即使只是在理论上,因为你首先检查它)取消引用 NULL 指针?
编辑:哦,你不知道对象是否是动态创建的。
I'd much prefer to use references everywhere but the moment you use an STL container you have to use pointers unless you really want to pass complex types by value. And I feel dirty converting back to a reference, it just seems wrong.
Is it?
To clarify...
MyType *pObj = ...
MyType &obj = *pObj;
Isn't this 'dirty', since you can (even if only in theory since you'd check it first) dereference a NULL pointer?
EDIT: Oh, and you don't know if the objects were dynamically created or not.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
在尝试将指针转换为引用之前,请确保指针不为 NULL,并且只要引用存在,该对象就会保留在范围内(或保持分配状态,引用堆),这样就可以了,而且道德清白:)
Ensure that the pointer is not NULL before you try to convert the pointer to a reference, and that the object will remain in scope as long as your reference does (or remain allocated, in reference to the heap), and you'll be okay, and morally clean :)
使用取消引用的指针初始化引用绝对没问题,没有任何问题。如果
p
是一个指针,并且解除引用它是有效的(例如,它不为 null),那么*p
就是它指向的对象。您可以绑定对该对象的引用,就像将引用绑定到任何对象一样。显然,您必须确保引用不会比对象活得更久(就像任何引用一样)。例如,假设我传递了一个指向对象数组的指针。它也可以是迭代器对、对象向量或对象
map
,但为了简单起见,我将使用数组。每个对象都有一个函数order
,返回一个整数。我要在每个对象上调用一次bar
函数,按照order
值递增的顺序:我的示例初始化的引用是函数参数而不是直接变量,但我可以有效地完成:
显然
vector
是不正确的,因为那时我将在 copy 上调用bar
每个对象按顺序排列,而不是每个对象按顺序排列。bar
采用非常量引用,因此除了性能或其他任何因素之外,如果bar
修改输入,这显然是错误的。智能指针向量或 boost 指针向量也将是错误的,因为我不拥有数组中的对象,并且当然不能释放它们。也可能不允许对原始数组进行排序,或者如果它是
map
而不是数组,则不可能对原始数组进行排序。Initialising a reference with a dereferenced pointer is absolutely fine, nothing wrong with it whatsoever. If
p
is a pointer, and if dereferencing it is valid (so it's not null, for instance), then*p
is the object it points to. You can bind a reference to that object just like you bind a reference to any object. Obviously, you must make sure the reference doesn't outlive the object (like any reference).So for example, suppose that I am passed a pointer to an array of objects. It could just as well be an iterator pair, or a vector of objects, or a
map
of objects, but I'll use an array for simplicity. Each object has a function,order
, returning an integer. I am to call thebar
function once on each object, in order of increasingorder
value:The reference that my example has initialized is a function parameter rather than a variable directly, but I could just have validly done:
Obviously a
vector<Foo>
would be incorrect, since then I would be callingbar
on a copy of each object in order, not on each object in order.bar
takes a non-const reference, so quite aside from performance or anything else, that clearly would be wrong ifbar
modifies the input.A vector of smart pointers, or a boost pointer vector, would also be wrong, since I don't own the objects in the array and certainly must not free them. Sorting the original array might also be disallowed, or for that matter impossible if it's a
map
rather than an array.否。您还能如何实现
operator=
?您必须取消引用this
才能返回对您自己的引用。请注意,尽管我仍然按值将项目存储在 STL 容器中 - 除非您的对象很大,否则堆分配的开销将意味着您使用更多的存储空间,并且效率较低。只是按值存储该项目。
No. How else could you implement
operator=
? You have to dereferencethis
in order to return a reference to yourself.Note though that I'd still store the items in the STL container by value -- unless your object is huge, overhead of heap allocations is going to mean you're using more storage, and are less efficient, than you would be if you just stored the item by value.
需要明确的是:STL 容器被设计为支持某些语义(“值语义”),例如“容器中的项目可以复制”。由于引用不可重新绑定,因此它们不支持值语义(即,尝试创建
std::vector
或std::list< /代码>)。您不能将引用放入 STL 容器,这是正确的。
一般来说,如果您使用引用而不是普通对象,那么您要么使用基类并希望避免切片,要么尝试避免复制。是的,这意味着如果您想将项目存储在 STL 容器中,那么您将需要使用指针来避免切片和/或复制。
并且,是的,以下是合法的(尽管在这种情况下,不是很有用):
那不重要。在上面的示例中,
x
位于堆栈上,我们将指向x
的指针存储在pointers_to_vectors
中。当然,pointers_to_vectors 在内部使用动态分配的数组(当向量超出范围时删除该数组),但是数组保存的是指针,而不是指向的东西。当pointers_to_ints
超出范围时,内部int*[]
会被delete[]
删除,但int*
code> 不能删除
。事实上,这使得在 STL 容器中使用指针变得很困难,因为 STL 容器不会管理所指向对象的生命周期。您可能想查看 Boost 的指针容器库。否则,您要么 (1) 使用智能指针的 STL 容器(例如对于 STL 容器来说是合法的 boost:shared_ptr),要么 (2) 管理所指向对象的生命周期其他方式。您可能已经在做 (2)。
Just to be clear: STL containers were designed to support certain semantics ("value semantics"), such as "items in the container can be copied around." Since references aren't rebindable, they don't support value semantics (i.e., try creating a
std::vector<int&>
orstd::list<double&>
). You are correct that you cannot put references in STL containers.Generally, if you're using references instead of plain objects you're either using base classes and want to avoid slicing, or you're trying to avoid copying. And, yes, this means that if you want to store the items in an STL container, then you're going to need to use pointers to avoid slicing and/or copying.
And, yes, the following is legit (although in this case, not very useful):
That's not important. In the above sample,
x
is on the stack and we store a pointer tox
in thepointers_to_vectors
. Sure,pointers_to_vectors
uses a dynamically-allocated array internally (anddelete[]
s that array when thevector
goes out of scope), but that array holds the pointers, not the pointed-to things. Whenpointers_to_ints
falls out of scope, the internalint*[]
isdelete[]
-ed, but theint*
s are notdelete
d.This, in fact, makes using pointers with STL containers hard, because the STL containers won't manage the lifetime of the pointed-to objects. You may want to look at Boost's pointer containers library. Otherwise, you'll either (1) want to use STL containers of smart pointers (like
boost:shared_ptr
which is legal for STL containers) or (2) manage the lifetime of the pointed-to objects some other way. You may already be doing (2).我的回答并没有直接解决您最初的担忧,但您似乎遇到了这个问题,因为您有一个存储指针类型的 STL 容器。
Boost 提供了 ptr_container 库来解决这些问题情况类型。例如,ptr_vector 内部存储指向类型的指针,但通过其接口返回引用。请注意,这意味着容器拥有指向实例的指针并将管理其删除。
这是一个演示这个概念的简单示例。
My answer doesn't directly address your initial concern, but it appears you encounter this problem because you have an STL container that stores pointer types.
Boost provides the ptr_container library to address these types of situations. For instance, a
ptr_vector
internally stores pointers to types, but returns references through its interface. Note that this implies that the container owns the pointer to the instance and will manage its deletion.Here is a quick example to demonstrate this notion.
如果您希望容器实际上包含动态分配的对象,则不应使用原始指针。使用
unique_ptr
或任何类似的合适类型。If you want the container to actually contain objects that are dynamically allocated, you shouldn't be using raw pointers. Use
unique_ptr
or whatever similar type is appropriate.这没有任何问题,但请注意,在机器代码级别,引用通常与指针相同。因此,当分配给引用时,通常指针并没有真正取消引用(没有内存访问)。
因此,在现实生活中,引用可能为 0,并且在使用引用时会发生崩溃 - 这可能会比其赋值晚得多。
当然,到底发生什么在很大程度上取决于编译器版本和硬件平台以及编译器选项和引用的确切用法。
正式地,取消引用 0 指针的行为是未定义,因此任何事情都可能发生。这个任何事情包括它可能立即崩溃,但也包括它可能稍后崩溃或永远不会崩溃。
因此,请务必确保永远不要将 0 指针分配给引用 - 像这样的错误很难找到。
编辑:将“通常”改为斜体,并添加有关官方“未定义”行为的段落。
There's nothing wrong with it, but please be aware that on machine-code level a reference is usually the same as a pointer. So, usually the pointer isn't really dereferenced (no memory access) when assigned to a reference.
So in real life the reference can be 0 and the crash occurs when using the reference - what can happen much later than its assignemt.
Of course what happens exactly heavily depends on compiler version and hardware platform as well as compiler options and the exact usage of the reference.
Officially the behaviour of dereferencing a 0-Pointer is undefined and thus anything can happen. This anything includes that it may crash immediately, but also that it may crash much later or never.
So always make sure that you never assign a 0-Pointer to a reference - bugs likes this are very hard to find.
Edit: Made the "usually" italic and added paragraph about official "undefined" behaviour.