通过右值传递给 unordered_map 时释放内存

Posted

技术标签:

【中文标题】通过右值传递给 unordered_map 时释放内存【英文标题】:the memory is released when passing to unordered_map by rvalue 【发布时间】:2021-01-05 13:07:43 【问题描述】:

我用-std=c++17 构建它并尝试了g++clang++,例如clang++ -std=c++17 <file>。它显示了相同的结果。

unordered_map

将 unordered_map 传递给函数中的右值参数,并将其分配给另一个引用。并且内存是不允许出函数的。

#include <iostream>
#include <string>
#include <unordered_map>
#include <list>

using namespace std;

typedef unordered_map<string, string> kw_t;

struct Bar 
    kw_t &foo;
    string bar;
;

list<Bar> bars;

void test(kw_t &&foo) 
    cout << &foo["a"] << endl;
    bars.emplace_back(Bar  .foo = foo, .bar = "bar" );
    cout << &bars.front().foo["a"] << endl;


int main()

    test("a", "b");
    cout << &bars.front().foo["a"] << endl;
    return 0;

它有输出:

0x1f3ded8
0x1f3ded8
[1]    9776 segmentation fault (core dumped)  ./a.o

列表

但是对于其他的类,比如list或者自定义的struct,代码可以工作。

#include <iostream>
#include <list>
#include <string>

using namespace std;

typedef list<string> args_t;


struct Bar 
    args_t &foo;
    string bar;
;

list<Bar> bars;

void test(args_t &&foo) 
    cout << &foo.front() << endl;
    bars.emplace_back(Bar  .foo = foo, .bar = "bar" );
    cout << &bars.front().foo.front() << endl;


int main()

    test("a", "b");
    cout << &bars.front().foo.front() << endl;
    return 0;

打印出来了:

0x15a7ec0
0x15a7ec0
0x15a7ec0

为什么第二个可以,第一个不行?

编辑1:

clang 版本 7.1.0

g++ (GCC) 9.3.0

【问题讨论】:

您在这两种情况下都创建了一个悬空引用foo。所以它们都不起作用。 @user7860670 但是第二种情况有效。这是编译器的错误行为吗? 我认为应该在声明时初始化引用。新版本的 C++ 是否发生了变化? 第二个版本不行,和第一个一样。唯一的区别是,在第一种情况下,UB 表现为分段错误。 @ArdahanKisbet 所有的引用都在这里正确初始化。 【参考方案1】:

为什么第二个可以,第一个不行?

在这两种情况下,程序的行为都是未定义的。因此,它“可以”、“可能”或“被允许”出现工作(无论你认为什么“正在工作”)。或者不“工作”。或有任何其他行为。

为了澄清,引用bars.front().foo绑定到的临时对象的生命周期已经结束,因此引用无效。通过无效引用调用成员函数会导致未定义的行为。

这是编译器的错误行为吗?

没有。编译器行为正确。但是,您的程序已损坏。

【讨论】:

以上是关于通过右值传递给 unordered_map 时释放内存的主要内容,如果未能解决你的问题,请参考以下文章

将多个右值和左值传递给函数而不创建重载

如何将右值引用从调用者传递给被调用者

std::unordered_map 析构函数不释放内存?

无序映射的左值到右值转换

将 std::forward_as_tuple() 结果传递给可能从该对象的右值引用成员移动的多个函数?

C++ 传递向量(左值到右值)