This example fails to compile unless I uncomment the default constructor declaration:
#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))...)
| ^
When I uncomment the default constructor declaration and successfully compile, the breadcrumbs show that the default constructor is not ever called.
What is going on here? A similar problem is due to a most vexing parse, but without any explicit constructor calls I am not sure if that is the case here.
This answer provides hints as to why an unordered_map would implicitly call a default constructor. Is the issue some combination of the documented behavior described and MVP?
When the compiler compiles this line:
foo f3 = b.getElem(1);
1
is passed as a parameter to a function (unless a whole lot of optimization magic occured, which is not guaranteed). This function cannot know that 1
will never be a missing key. As such, the code that allocates an entry in the map is called. And what is passed to this code, if the key is missing ? Yep, a default-constructed foo
.
So, in a nutshell, you know that
the default constructor is not ever called
but the compiler and linker don't.