[英]No narrowing warnings when using `emplace_back` instead of `push_back`
我的同事遇到了emplace_back
的意外问题,我正试图解决这个问题。 以下test.cpp
是重现该问题的最小示例:
#include <vector>
class A {
public:
explicit A(int /*unused*/) {}
};
int main() {
double foo = 4.5;
std::vector<A> a_vec{};
a_vec.emplace_back(foo); // No warning with Wconversion
A a(foo); // Gives compiler warning with Wconversion as expected
}
使用 g++ 8.3.0 编译会产生以下警告:
$ g++ -Wconversion test.cpp -o test
test.cpp: In function ‘int main()’:
test.cpp:10:10: warning: conversion from ‘double’ to ‘int’ may change value [-Wfloat-conversion]
A a(bar); // Gives compiler warning with Wconversion as expected
因此,在构造简单的 object 时会捕获隐式转换,但在调用emplace_back
时不会捕获。
为什么emplace_back
没有警告?
这是默认分配器如何构造A
结果。 当您执行A a{foo, bar}
时,您正在使用列表初始化,并且需要进行缩小转换才能发出诊断。 使用默认分配器,它使用
::new (static_cast<void*>(p)) T(std::forward<Args>(args)...)
其中p
是指向向量数据元素的指针, T
是向量的value_type
。 在这里,他们使用括号而不是大括号,并且允许使用括号缩小转换,因此您不会看到诊断消息。
如果您编写了自己的分配器
::new (static_cast<void*>(p)) T{std::forward<Args>(args)...}
然后你会得到警告。
为了获得警告,您需要编译:
$ g++ -Wsystem-headers -Wconversion test.cpp -o test
In file included from /usr/include/c++/8/vector:60,
from test.cpp:1:
/usr/include/c++/8/bits/stl_algobase.h: In function ‘constexpr int std::__lg(int)’:
/usr/include/c++/8/bits/stl_algobase.h:1001:44: warning: conversion from ‘long unsigned int’ to ‘int’ may change value [-Wconversion]
{ return sizeof(int) * __CHAR_BIT__ - 1 - __builtin_clz(__n); }
^
/usr/include/c++/8/bits/stl_algobase.h: In function ‘constexpr unsigned int std::__lg(unsigned int)’:
/usr/include/c++/8/bits/stl_algobase.h:1005:44: warning: conversion from ‘long unsigned int’ to ‘unsigned int’ may change value [-Wconversion]
{ return sizeof(int) * __CHAR_BIT__ - 1 - __builtin_clz(__n); }
^
In file included from /usr/include/x86_64-linux-gnu/c++/8/bits/c++allocator.h:33,
from /usr/include/c++/8/bits/allocator.h:46,
from /usr/include/c++/8/vector:61,
from test.cpp:1:
/usr/include/c++/8/ext/new_allocator.h: In instantiation of ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = A; _Args = {double&}; _Tp = A]’:
/usr/include/c++/8/bits/alloc_traits.h:475:4: required from ‘static void std::allocator_traits<std::allocator<_Tp1> >::construct(std::allocator_traits<std::allocator<_Tp1> >::allocator_type&, _Up*, _Args&& ...) [with _Up = A; _Args = {double&}; _Tp = A; std::allocator_traits<std::allocator<_Tp1> >::allocator_type = std::allocator<A>]’
/usr/include/c++/8/bits/vector.tcc:103:30: required from ‘void std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {double&}; _Tp = A; _Alloc = std::allocator<A>]’
test.cpp:9:25: required from here
/usr/include/c++/8/ext/new_allocator.h:136:4: warning: conversion from ‘double’ to ‘int’ may change value [-Wfloat-conversion]
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
警告不再那么清楚,因为它发生在系统 header 中。 请注意,仅使用-Wsystem-headers
标志是不够的,需要同时使用-Wsystem-headers
和-Wconversion
才能捕捉到这一点。
在push_back
的情况下,使用-Wnarrowing
来获得警告就足够了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.