临时对象的寿命扩展:包含函数调用的完整表达式是什么?

发布于 2025-02-05 05:44:34 字数 1904 浏览 3 评论 0 原文

简介

说有一个容器类,该类存储 widget 对象。 有一个迭代器类负责导航此类容器。此迭代器类( myiterator )将const-Reference在其构造函数中的 stupt 的向量上进行,它需要在容器中的正确元素上迭代。代码可能看起来像这样:

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;
};

问题

我对 rvalue s对const引用的绑定以及寿命扩展的工作方式感到好奇的

vec 可以绑定到临时 rvalue ,但一旦 rvalue 的一生结束了。因此,这样的代码旨在为object mycontainer 创建一个迭代器是错误的:

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

cppReference 我发现:

每当引用绑定到临时对象或其子对象时,延长临时对象的寿命以匹配参考的寿命(...) 此寿命规则有以下例外:(...)

  • 存在函数调用中的参考参数的临时绑定,直到包含该函数呼叫的完整表达式结束:如果函数返回了一个参考,该引用量超过了完整表达式,则将变成一个悬挂参考。

突出显示的部分的问题

使我探讨了这个问题:这件代码是否会成功获得 mycontainer 的内容的过滤版本?

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

第二个论点是一个 rvalue ,因此存在创建悬而未决的参考的危险,但是我对文档的理解是, rvalue 的一生将被延长 std :: copy_if 的结尾,这没关系。它是哪一个?

注意:我知道问题和设计似乎有些奇怪,但它以我在野外发现的真实代码为灵感。我对一生延长的限制感兴趣,而不是提出不同的设计,这会使问题无关紧要。

Introduction

Say there is a Container class which stores Widget objects.
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. 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 rvalues to const references, and how the lifetime extensions work.

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. So code like this, aimed to create an iterator for object myContainer is wrong:

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:

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?

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. 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.

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

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

发布评论

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

评论(1

下雨或天晴 2025-02-12 05:44:34

是的,整个 std :: copy_if 呼叫是 full-expression ,临时 std :: vector&lt; supp&gt; 才会仅在之后被销毁呼叫返回。

这与副价值函数参数不同。如果构造函数采用 std :: vector&lt; supp&gt; ,而不是 const std :: vector&lt; quatp&gt;&gt;&gt;&amp; ,那么是否将实现是否定义对象。当构造师返回时,长期生活或立即被摧毁。


全表达是。没有一个具体案件(例如未评估的操作数,即时调用等)在此处适用,因此相关条件是:

不是另一个表达式的亚表达,否则不是全表达的一部分。

copy_if 调用表达式是该语句中应用的唯一一个(在lambda主体之外)。

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.

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.


A full-expression is one of the expressions listed in [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).

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