简体   繁体   English

临时对象的生命周期延长:包含函数调用的完整表达式是什么?

[英]Lifetime extension of temporary objects: what is the full expression containing a function call?

Introduction介绍

Say there is a Container class which stores Widget objects.假设有一个Container类存储Widget对象。 There is an iterator class in charge of navigating such container.有一个迭代器类负责导航这样的容器。 This iterator class ( MyIterator ) takes a const-reference to a vector of Stuff in its constructor, which it needs to iterate over the right elements in the container.这个迭代器类( MyIterator )在其构造函数中接受一个对Stuff向量的常量引用,它需要迭代容器中的正确元素。 The code may look like this:代码可能如下所示:

class MyIterator
{
public:
    MyIterator(
        const Container& container,    // Container to be navigated
        const std::vector<Stuff>& vec) // Parameter which controls the behaviour of the iteration
    : container(container)
    , stuffVector(vec)
    {}
    
    ...

private:
    const Container& container;
    const std::vector<Stuff>& stuffVector;
};

The problem问题

I'm curious about the binding of rvalue s to const references, and how the lifetime extensions work.我很好奇rvalue与 const 引用的绑定,以及生命周期扩展如何工作。

While vec can be bound to a temporary rvalue , that will cause stuffVector to be a dangling reference once the rvalue 's lifetime is over.虽然vec可以绑定到临时rvalue ,但一旦rvalue的生命周期结束,这将导致stuffVector成为悬空引用。 So code like this, aimed to create an iterator for object myContainer is wrong:所以像这样旨在为对象myContainer创建迭代器的代码是错误的:

MyIterator it = {myContainer, {stuff1, stuff2, stuff3}};
// Here it.stuffVector is a dangling reference!

Reading up on lifetime extension of temporary objects in cppreference I found:阅读cppreference中临时对象的生命周期延长我发现:

Whenever a reference is bound to a temporary object or to a subobject thereof, the lifetime of the temporary object is extended to match the lifetime of the reference (...) There are following exceptions to this lifetime rule: (...)每当引用绑定到临时对象或其子对象时,临时对象的生命周期就会延长以匹配引用的生命周期(...)此生命周期规则有以下例外:(...)

  • a temporary bound to a reference parameter in a function call exists until the end of the full expression containing that function call : if the function returns a reference, which outlives the full expression, it becomes a dangling reference.函数调用中引用参数的临时绑定一直存在,直到包含该函数调用的完整表达式结束:如果函数返回一个引用,该引用比完整表达式的寿命长,则它成为一个悬空引用。

The question问题

The highlighted part leads me to this question: would this piece of code succeed in getting a filtered version of the contents of myContainer ?突出显示的部分让我想到了这个问题:这段代码能否成功获得myContainer内容的过滤版本?

std::vector<Widget> filteredWidgets;
std::copy_if (
    MyIterator{myContainer, {stuff1, stuff2, stuff3}},
    MyContainer.end(),
    std::back_inserter(filteredWidgets),
    [&](Widget w) { return ...; });

The second argument is an rvalue , so there is the danger of creating a dangling reference, but my understanding of the documentation is that the rvalue 's lifetime will be extended untill the end of std::copy_if , so it would be fine.第二个参数是rvalue ,因此存在创建悬空引用的危险,但我对文档的理解是rvalue的生命周期将延长到std::copy_if结束,所以没问题。 Which one is it?哪一个?

NOTE: I am aware the problem and the design, as stated, might seem a bit strange, but it's inspired in real code I've found in the wild.注意:我知道问题和设计,如前所述,可能看起来有点奇怪,但它的灵感来自我在野外发现的真实代码。 I'm interested in the limits of the lifetime extension, not so much in coming up with different designs which would make the question irrelevant.我对延长寿命的限制感兴趣,而不是想出不同的设计,这会使问题变得无关紧要。

Yes, the whole std::copy_if call is the full-expression and the temporary std::vector<Stuff> will be destroyed only after the call returns.是的,整个std::copy_if调用是完整的表达式,临时的std::vector<Stuff>只会在调用返回后被销毁。

This is different from by-value function parameters.这与按值函数参数不同。 If the constructor took a std::vector<Stuff> instead of a const std::vector<Stuff>& , then it would be implementation-defined whether the object lives that long or is destroyed immediately when the constructor returns.如果构造函数采用std::vector<Stuff>而不是const std::vector<Stuff>& ,那么当构造函数返回时,对象是存活那么久还是立即销毁将由实现定义。


A full-expression is one of the expressions listed in [intro.execution]/5 .完整表达式是[intro.execution]/5中列出的表达式之一。 None of the specific cases (such as unevaluated operands, immediate invocations, etc.) apply here and so falling through, the relevant condition is:任何特定情况(例如未评估的操作数、立即调用等)都不适用于此处,因此不适用,相关条件是:

an expression that is not a subexpression of another expression and that is not otherwise part of a full-expression.一个表达式,它不是另一个表达式的子表达式,也不是完整表达式的一部分。

The copy_if call expression is the only one in that statement to which this applies (outside of the lambda body). copy_if调用表达式是该语句中唯一适用的(在 lambda 主体之外)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM