Do const references in structured bindings extend the lifetime of the decomposed object?

馋奶兔 提交于 2020-01-01 07:43:08

问题


Does writing const auto& [a, b] = f(); guarantee extending the lifetime of the object returned from f(), or at least the objects a and b are bound to? Reading through the proposal I don't see anything obvious in the language to make me sure that it does unless it's just covered by something else. However, the following doesn't extend the lifetime of the temporary, so I don't see how it would be covered:

const auto& a = std::get<0>(f());

At the top of the paper it seems to suggest that it is covered

the cv-qualifiers and ref-qualifier of the decomposition declaration are applied to the reference introduced for the initializer, not for the individual member aliases

But in the proposed wording for the actual standard, the closest mention I see is below, though I'm not sure how to read it to get the guarantee I'm looking for:

if e is an unparenthesized id-expression naming an lvalue or reference introduced from the identifier-list of a decomposition declaration, decltype(e) is the referenced type as given in the specification of the decomposition declaration

It seems that gcc and clang both extend the lifetime of the object returned until the end of the scope based on a wandbox experiment. An uglier one implementing all the bells and whistles for my own type seems to extend the lifetime of the outer object and its other data members.

Though almost certainly the authors' intent(s), I'd like to know for sure that the language guarantees this is safe.


回答1:


Yes. The trick is to realize that despite the appearance, the portion of a structured binding declaration before the [ doesn't apply to the names in the identifier-list. They apply instead to the variable introduced implicitly by the declaration. [dcl.struct.bind]/1:

First, a variable with a unique name e is introduced. If the assignment-expression in the initializer has array type A and no ref-qualifier is present, e has type cv A and each element is copy-initialized or direct-initialized from the corresponding element of the assignment-expression as specified by the form of the initializer. Otherwise, e is defined as-if by

attribute-specifier-seqoptdecl-specifier-seq ref-qualifieropte initializer ;

where the declaration is never interpreted as a function declaration and the parts of the declaration other than the declarator-id are taken from the corresponding structured binding declaration.

The names are then defined to either be aliases for the elements of e or references bound to the result of calling get on e.

In your example, it's as if by (assuming that f returns a two-element std::tuple):

const auto& e = f(); // 1
using E = remove_reference_t<decltype((e))>;
std::tuple_element<0, E>::type& a = get<0>(e);
std::tuple_element<1, E>::type& b = get<1>(e);

(Except that decltype(a) and decltype(b) gets the special treatment to hide their referenceness.)

It should be pretty obvious that line #1 does extend the lifetime of f's return value.



来源:https://stackoverflow.com/questions/41176231/do-const-references-in-structured-bindings-extend-the-lifetime-of-the-decomposed

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