【问题标题】:Why do I need to declare a default constructor in order to compile when returning an unordered_map value?为什么在返回 unordered_map 值时需要声明默认构造函数才能编译?
【发布时间】:2021-06-25 23:00:05
【问题描述】:

除非我取消注释默认构造函数声明,否则此示例无法编译:

#include<unordered_map>
#include <iostream>

struct foo{
    int data;
    /*foo(){
        data = 0;
        std::cout << "DEFAULT\n";
    }*/
    foo(int d){
        data = d;
        std::cout << "PARAM\n";
    }
};

struct bar{
    std::unordered_map<int, foo> map;
    foo getElem(int i){
        return map[i];
    }
};

int main() {
    bar b;
    foo f1(1);
    foo f2(2);
    b.map.insert({1,f1});
    b.map.insert({2,f2});

    foo f3 = b.getElem(1);
}
/opt/compiler-explorer/gcc-10.2.0/include/c++/10.2.0/tuple:1689:70: error: no matching function for call to 'foo::foo()'
 1689 |         second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...)
      |                                                                      ^

当我取消注释默认构造函数声明并成功编译时,面包屑显示从未调用过默认构造函数。

这里发生了什么?类似的问题是由于most vexing parse,但没有任何显式的构造函数调用,我不确定这里是否是这种情况。

This answer 提供了关于为什么 unordered_map 会隐式调用默认构造函数的提示。问题是所描述的记录行为和 MVP 的某种组合吗?

link to godbolt

【问题讨论】:

  • the breadcrumbs show that the default constructor is not ever called.可能是,如果 return map[i]; 访问一个不存在的元素。

标签: c++ unordered-map default-constructor most-vexing-parse


【解决方案1】:

当编译器编译这一行时:

foo f3 = b.getElem(1);

1 作为参数传递给函数(除非发生了很多优化魔法,这是无法保证的)。此函数无法知道1 永远不会是丢失的键。因此,调用在映射中分配条目的代码。如果缺少密钥,则传递给此代码的内容是什么?是的,默认构造的foo

所以,简而言之,你知道

从未调用过默认构造函数

但编译器和链接器没有。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-20
    • 2019-03-01
    • 2019-05-17
    • 1970-01-01
    • 1970-01-01
    • 2012-12-25
    相关资源
    最近更新 更多