Exact correspondence between r-value references and pointers?

青春壹個敷衍的年華 提交于 2020-08-05 13:31:43

问题


This is a general question about symmetry between pointer and reference types in the C++ language.

Is this table of correspondence meaningful in C++ (C++11 and beyond)?

+-----------+----------------+
| Reference | Pointer        |
|-----------|----------------|
| T&        | T* const       |
| T const&  | T const* const |
| T&&       | ???*           |
+-----------+----------------+

and if some, what would correspond to ???* ?. (Any additional rows are missing?)

(T&& is for a concrete type T, not a deduced type. See @ComicSansMS answer for the trailing const.)

My guess it will correspond to something like std::move_iterator<T*>, but it is not a built-in language feature and it seems to create a bunch of other problems (like std::reference_wrapper does).

Is the language missing some kind of r-value pointer to be more symmetric? Or better said something that generates r-values on derreference (for example a moved object -- or a even a copy).

I know that r-value references correspond to thing that "do not have a name", however that doesn't seem to be constradictory if that samething is only obtained for a deference operation *.


NOTE 1:

I see std::move_iterator<It>::operator->() is deprecated in C++20. Which I am not sure what it means, perhaps it means that it can't be implemented, optionally, sometimes. This question is relevant to this deprecation because in principle std::move_iterator<It>::operator->() could return ???* rather than pointer. (Or return move_iterator<pointer>, although that will generate a infinite regress of ->() operators... unless there is a true pointer for r-values to terminate.)


NOTE 2: A candidate missing row missing that I can imagine is:

| void& (not a thing)  | void*     |

but I think it is not related to the correspondence asked in the question, but a normal irregularity of void in the language.


回答1:


There is no "symmetry between pointer and reference types". Or at least, there isn't intended to be one. You can interpret the language however you like, but any symmetry you see there is accidental.

In most ways lvalue and rvalue references work the same way. The principal differences are that you can distinguish between them by type (and can therefore overload functions or affect template instantiation based on them), and they have different rules for what objects they bind, particularly under overload resolution. The purpose of the distinction is to make the type system more accurately convey the value category of the source object, so that the user can know more about what is reasonable to do with the referenced object.

Pointers don't need to do this, so they don't need to make this distinction.




回答2:


Is this table of correspondence meaningful in C++ (C++11 and beyond)?

It can be a useful mental model to think of references as a syntactically different way to achieve pointer semantics. The crucial thing missing from your table is that the equivalent to a reference is not a pointer, but a const pointer:

| Reference | Pointer        |
|-----------|----------------|
| T&        | T* const       |
| T const&  | T const* const |

Note how this is a very rough approximation of the truth that quickly breaks down. All the caveats from @Nicol Bolas's answer apply here. Also, T const& will bind to temporaries, while T const* const will very much not.

Now about the missing row for T&&. The mental model for T&& here is a reference that you are always allowed to move from. In a function body, a T&& parameter to that function can be treated exactly as if it were a T& parameter, with special semantics only kicking in when it comes to moving. For a caller of said function on the other hand, T&& is unlike any of the known reference or pointer types in that it not only will bind to unnamed temporaries (like T const& does), but it will actually only bind to temporaries and nothing else. You may be able to figure out for yourself why the equivalent concept for a pointer, while conceivable, would not have been a very useful addition to the language.

Regarding your note 1: Deprecated means that the thing is flagged for removal from the standard. While implementations will still support it for the time being, that is purely for backwards compatibility and new code should steer clear of using deprecated functionality. The reason this functionality on move_iterator should no longer be used is exactly the absence of the concept of a pointer-that-is-safe-to-use-from from the language.

Regarding your note 2: Due to historical reasons, another crucial difference between pointers and references is that pointer types are interconvertible to some degree. That is a pointer T* can be cast to a U* even if T and U are unrelated types. This behavior is by many considered a highly dangerous legacy from C and deemed largely undesirable. References do not allow such conversions in any case. This should give you a hint as to why void& is not a valid datatype in the language.



来源:https://stackoverflow.com/questions/61313437/exact-correspondence-between-r-value-references-and-pointers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!