为什么v.emplace_back(nullptr);
编译(然后导致运行时错误)但出现编译器错误v.push_back(nullptr);
?
emplace_back
有些文章建议在大多数情况下使用push_back
,但emplace_back
会导致潜在的错误。什么时候应该避免使用emplace_back
?
#include <regex>
#include <vector>
int main() {
std::vector<std::regex> v;
v.emplace_back(nullptr); // runtime error
v.push_back(nullptr); // compile error
return 0;
}
<source>: In function 'int main()':
<source>:9:14: error: no matching function for call to 'std::vector<std::__cxx11::basic_regex<char> >::push_back(std::nullptr_t)'
9 | v.push_back(nullptr); // compile error
| ~~~~~~~~~~~^~~~~~~~~
push_back(nullptr)
在编译时失败,因为push_back
需要对要存储类型的对象的引用nullptr
(不是指针,因此不是合法的可空值)或可隐式转换为该类型的对象。不是对的有效引用std::regex
,并且不会隐式转换为std::regex
(采用单个指针的构造函数被explicit
精确标记以防止这种情况发生),因此在任何情况下这种类型(任何类型的指针类型)都不会起作用,并且这在编译时失败。它之所以能工作,
emplace_back
是因为nullptr
它是一种合法的显式构造类型std::regex
(构造函数之一接受它const CharT* s
作为唯一参数)。因此,v.emplace_back(nullptr);
最终尝试做大致v.push_back(std::regex(nullptr));
会做的事情(但保证直接构造到存储中,没有临时变量随后会移动到存储中);它在所涉及的类型中完全合法,但它std::regex(nullptr)
是垃圾并且在运行时会失败。从语法上讲,根据构造函数的签名
std::regex
,您尝试执行的操作是合法的,只是在这种情况下空指针是一个无意义的参数(文档要求指向以空值终止的字符串的指针,但事实nullptr
并非如此)。基本上,您需要知道您存储
emplace_back
的内容才能正确使用。违反存储项构造函数的要求是导致此问题的原因,而不是问题emplace_back
本身。