通过右值数据成员延长临时的生命周期适用于聚合,但不适用于构造函数,为什么?

2024-05-18

我发现以下方案可以延长临时生命周期,我不知道是否应该,但确实如此。

struct S {
    std::vector<int>&& vec;
};

int main() {
    S s1{std::vector<int>(5)};      // construct with temporary
    std::cout << s1.vec[0] << '\n'; // fine, temporary is alive
}

然而,当S给定一个显式值构造函数,它不再是一个聚合,并且该方案因无效读取而失败s1.vec[0]

struct S {
    std::vector<int>&& vec;
    S(std::vector<int>&& v)
        : vec{std::move(v)}         // bind to the temporary provided
    { }
};

int main() {
    S s1{std::vector<int>(5)};      // construct with temporary
    std::cout << s1.vec[0] << '\n'; // not ok. invalid read on free'd memory
}

为什么这对聚合有效?我认为这与构造函数是一个实际的函数调用有关,基于我用 const lvalue refs 读到的内容。另外,有什么办法可以使后一种情况起作用吗?

有很多问题涉及使用 SO 上的左值引用来处理类似的情况。我发现如果我使用了 const 左值引用,它将无助于延长临时变量的生命周期,右值引用的规则是否相同?


TL;DR

聚合初始化可用于延长临时的、用户定义的构造函数不能做同样的事情,因为它实际上是一个函数调用。

Note: Both T const& and T&& apply in the case of aggregate-initalization and extending the life of temporaries bound to them.



什么是总计的?

struct S {                // (1)
  std::vector<int>&& vec;
};

为了回答这个问题,我们必须深入研究初始化和初始化之间的区别总计的和初始化班级类型,但首先我们必须确定什么是总计的 is:

8.5.1p1 骨料 [dcl.init.aggr]

An 总计的是一个数组或类(第 9 条),没有用户提供的构造函数(12.1),没有私有或受保护的非静态数据成员(第 11 条),没有基类(第 10 条),并且没有虚函数(10.3)

Note: The above means that (1) is an aggregate.



How are 骨料初始化?

之间的初始化总计的 and a "非聚合” 差异很大,这是直接来自标准的另一部分:

8.5.1p2 骨料 [dcl.init.aggr]

当聚合由初始化列表初始化时,如 8.5.4 中所指定,初始值设定项列表的元素被视为聚合成员的初始值设定项,按递增的下标或成员顺序。每个成员都是复制初始化从相应的初始化子句.

上面的引用表明我们正在初始化我们的成员总计的与初始化程序初始化子句,中间没有步骤。

struct A { std::string a; int b; };
A x { std::string {"abc"}, 2 };

从语义上讲,上面的内容相当于使用下面的内容初始化我们的成员,只是A::a and A::b在这种情况下只能通过x.a and x.b.

std::string A::a { std::string {"abc"} };
int         A::b { 2 };

如果我们改变类型A::a到右值引用,或const 左值引用, 我们将directly将用于初始化的临时用途绑定到x.a.

的规则右值引用, and const 左值引用,表示临时对象的生命周期将延长到宿主的生命周期,这正是将要发生的情况。



使用用户声明的构造函数进行初始化有何不同?

struct S {                    // (2)
    std::vector<int>&& vec;
    S(std::vector<int>&& v)
        : vec{std::move(v)}   // bind to the temporary provided
    { }
};

A 构造函数实际上只不过是一个奇特的函数,用于初始化class实例。适用于函数的规则也适用于它们。

在延长临时修复体的使用寿命方面没有什么区别。

std::string&& func (std::string&& ref) {
  return std::move (ref);
}

临时传递给func不会仅仅因为我们有一个参数声明为右值/左值引用而延长其生命周期。即使我们返回"same"参考,以便它可以在外部使用func,这不会发生。

这就是在构造函数中发生的事情(2),毕竟一个构造函数只是一个“奇特的功能" 用于初始化一个对象。

12.2p5 临时对象 [class.temporary]

引用绑定到的临时对象或引用绑定到的子对象的完整对象的临时对象在引用的生命周期内持续存在,但以下情况除外:

  • 构造函数构造函数初始化程序 (12.6.2) 中引用成员的临时绑定将持续存在,直到构造函数退出。

  • 函数调用 (5.2.2) 中对引用参数的临时绑定将持续存在,直到包含调用的完整表达式完成为止。

  • 函数返回语句 (6.6.3) 中绑定到返回值的临时变量的生命周期不会延长;临时值在 return 语句中完整表达式的末尾被销毁。

    • 临时绑定到 a 中的引用新的初始化器(5.3.4) 一直持续到包含以下内容的完整表达式完成新的初始化器.

Note: Do note that aggregate initialization through a new T { ... } differ from the previously mentioned rules.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通过右值数据成员延长临时的生命周期适用于聚合,但不适用于构造函数,为什么? 的相关文章

  • STL 迭代器:前缀增量更快? [复制]

    这个问题在这里已经有答案了 可能的重复 C 中的预增量比后增量快 正确吗 如果是 为什么呢 https stackoverflow com questions 2020184 preincrement faster than postinc
  • 如何在 Cassandra 中存储无符号整数?

    我通过 Datastax 驱动程序在 Cassandra 中存储一些数据 并且需要存储无符号 16 位和 32 位整数 对于无符号 16 位整数 我可以轻松地将它们存储为有符号 32 位整数 并根据需要进行转换 然而 对于无符号 64 位整
  • 随着时间的推移,添加到 List 变得非常慢

    我正在解析一个大约有 1000 行的 html 表 我从一个字符串中添加 10 个字符串 td 每行到一个list td
  • 如何连接重叠的圆圈?

    我想在视觉上连接两个重叠的圆圈 以便 becomes 我已经有部分圆的方法 但现在我需要知道每个圆的重叠角度有多大 但我不知道该怎么做 有人有主意吗 Phi ArcTan Sqrt 4 R 2 d 2 d HTH Edit 对于两个不同的半
  • 如何在 C++ 中标记字符串?

    Java有一个方便的分割方法 String str The quick brown fox String results str split 在 C 中是否有一种简单的方法可以做到这一点 The 增强分词器 http www boost o
  • 无限循环与无限递归。两者都是未定义的吗?

    无副作用的无限循环是未定义的行为 看here https coliru stacked crooked com view id 24e0a58778f67cd4举个例子参考参数 https en cppreference com w cpp
  • 访问外部窗口句柄

    我当前正在处理的程序有问题 这是由于 vista Windows 7 中增强的安全性引起的 特别是 UIPI 它阻止完整性级别较低的窗口与较高完整性级别的窗口 对话 就我而言 我想告诉具有高完整性级别的窗口进入我们的应用程序 它在 XP 或
  • 在 Unity 中实现 Fur with Shells 技术

    我正在尝试在 Unity 中实现皮毛贝壳技术 http developer download nvidia com SDK 10 5 direct3d Source Fur doc FurShellsAndFins pdf Fins 技术被
  • 使用 C# 中的 CsvHelper 将不同文化的 csv 解析为十进制

    C 中 CsvHelper 解析小数的问题 我创建了一个从 byte 而不是文件获取 csv 文件的类 并且它工作正常 public static List
  • 结构体的内存大小不同?

    为什么第一种情况不是12 测试环境 最新版本的 gcc 和 clang 64 位 Linux struct desc int parts int nr sizeof desc Output 16 struct desc int parts
  • C# - 当代表执行异步任务时,我仍然需要 System.Threading 吗?

    由于我可以使用委托执行异步操作 我怀疑在我的应用程序中使用 System Threading 的机会很小 是否存在我无法避免 System Threading 的基本情况 只是我正处于学习阶段 例子 class Program public
  • x:将 ViewModel 方法绑定到 DataTemplate 内的事件

    我基本上问同样的问题这个人 https stackoverflow com questions 10752448 binding to viewmodels property from a template 但在较新的背景下x Bind V
  • 两个类可以使用 C++ 互相查看吗?

    所以我有一个 A 类 我想在其中调用一些 B 类函数 所以我包括 b h 但是 在 B 类中 我想调用 A 类函数 如果我包含 a h 它最终会陷入无限循环 对吗 我能做什么呢 仅将成员函数声明放在头文件 h 中 并将成员函数定义放在实现文
  • C# 动态/expando 对象的深度/嵌套/递归合并

    我需要在 C 中 合并 2 个动态对象 我在 stackexchange 上找到的所有内容仅涵盖非递归合并 但我正在寻找能够进行递归或深度合并的东西 非常类似于jQuery 的 extend obj1 obj2 http api jquer
  • 对于某些 PDF 文件,LoadIFilter() 返回 -2147467259

    我正在尝试使用 Adob e IFilter 搜索 PDF 文件 我的代码是用 C 编写的 我使用 p invoke 来获取 IFilter 的实例 DllImport query dll SetLastError true CharSet
  • 当文件流没有新数据时如何防止fgets阻塞

    我有一个popen 执行的函数tail f sometextfile 只要文件流中有数据显然我就可以通过fgets 现在 如果没有新数据来自尾部 fgets 挂起 我试过ferror and feof 无济于事 我怎样才能确定fgets 当
  • C# 中最小化字符串长度

    我想减少字符串的长度 喜欢 这串 string foo Lorem ipsum dolor sit amet consectetur adipiscing elit Aenean in vehicula nulla Phasellus li
  • MySQL Connector C/C API - 使用特殊字符进行查询

    我是一个 C 程序 我有一个接受域名参数的函数 void db domains query char name 使用 mysql query 我测试数据库中是否存在域名 如果不是这种情况 我插入新域名 char query 400 spri
  • 指针和内存范围

    我已经用 C 语言编程有一段时间了 但对 C 语言还是很陌生 有时我对 C 处理内存的方式感到困惑 考虑以下有效的 C 代码片段 const char string void where is this pointer variable l
  • 使用 WGL 创建现代 OpenGL 上下文?

    我正在尝试使用 Windows 函数创建 OpenGL 上下文 现代版本 基本上代码就是 创建窗口类 注册班级 创建一个窗口 choose PIXELFORMATDESCRIPTOR并设置它 创建旧版 OpenGL 上下文 使上下文成为当前

随机推荐