std::copy和std::vector::assign的转换警告

12

当一个浮点数被插入到 std::vector<int> 中时,这个数字必须通过某种方式进行四舍五入转换。通常情况下,这会改变数字,例如1.5 会变成1或2,我希望编译器至少能警告这种转换。因此我在 g++ 或 clang++ 上使用 -Wconversion 标志。这将启用对 std::vector::push_back 或直接赋值的警告,但不适用于 std::copystd::vector::assign(iterator first, iterator end)

现在我的问题是:如何获得关于 std::copystd::vector::assign 的转换警告?

这是我的示例程序:

#include <iostream>
#include <vector>
#include <algorithm>

using source_type = std::vector<double>;
using target_type = std::vector<int>;

int main() {
    source_type vsource;
    target_type vtarget1;
    target_type vtarget2;
    target_type vtarget3;
    target_type vtarget4;

    // Fill source with a number
    vsource.push_back(1.5);

    // This will give a compiler warning as expected
    vtarget1.push_back(vsource.at(0));

    // This does not give a warning, why not?
    vtarget2.assign(vsource.begin(), vsource.end());

    // Also this does not give a warning, why not?
    vtarget3.assign(vsource.size(), 0);
    std::copy(vsource.begin(), vsource.end(), vtarget3.begin());


    // The following should be equivalent to std::copy according to
    // http://www.cplusplus.com/reference/algorithm/copy/?kw=copy
    // Here we get a warning as expected (in contrast to std::copy).
    vtarget4.assign(vsource.size(), 0);
    auto source = vsource.begin();
    auto target = vtarget4.begin();
    while (source != vsource.end()) {
       *target = *source;
       ++target; ++source;
    }

    std::cout << vsource.at(0)  << " "
              << vtarget1.at(0) << " "
              << vtarget2.at(0) << " "
              << vtarget3.at(0) << " "
              << vtarget4.at(0) << std::endl;

    return 0;
}

我使用以下编译器:

g++ -Wall -Wextra -Wconversion -std=c++11 -pedantic 
clang++ -Wall -Wextra -Wconversion -std=c++11 -pedantic

我只得到了两个警告,我希望能再多一些:

question.cpp:22:24: warning: implicit conversion turns floating-point number into integer: 'value_type' (aka 'double')
      to 'value_type' (aka 'int') [-Wfloat-conversion]
    vtarget1.push_back(vsource.at(0));

question.cpp:40:18: warning: implicit conversion turns floating-point number into integer: 'double' to 'int'
      [-Wfloat-conversion]
       *target = *source;

阅读关于 -Wsystem-headers 的内容。 - o11c
@o11c 好的,使用“-Wsystem-headers”选项,我认为我看到了std::copy(vsource.begin(), vsource.end(), vtarget3.begin());上的警告,但是我没有在vtarget2.assign(vsource.begin(), vsource.end());上看到警告。不幸的是,还有太多其他的警告。如果这是正确的方法,我就迷失了 :( - Pates
2
@Pates,你没有看到assign的警告,是因为(至少在libstdc++中),std::vector::assign最终会调用std::copy来复制数据。因此只需要在一个地方警告转换即可。 - Miles Budnek
1
具体来说,它最终通过 assign -> _M_assign_dispatch -> _M_assign_aux -> _M_allocate_and_copy -> 根据当前大小/容量,std::copy 和/或 std::__uninitialized_copy_a -> std::uninitialized_copy -> std::__uninitialized_copy<false>::__uninit_copy -> std::copy 进行处理。因此,在静态情况下,有 4 次对 std::copy 的调用。 - o11c
3
push_back 指定了需要传入一个 int,因此类型转换发生在你的代码中。但是尝试使用 emplace_back - o11c
显示剩余3条评论
1个回答

2
您可以使用以下标志-std=c++11 -Wfloat-conversion -Wsystem-headers,使GCC对此LOC至少发出警告。
std::copy(vsource.begin(), vsource.end(), vtarget3.begin());

你可以在这里看到。

输出结果如下:

<source>: In function 'int main()':

<source>:21:34: warning: conversion from '__gnu_cxx::__alloc_traits<std::allocator<double>, double>::value_type' {aka 'double'} to 'std::vector<int>::value_type' {aka 'int'} may change value [-Wfloat-conversion]

21 |     vtarget1.push_back(vsource.at(0));

   |                        ~~~~~~~~~~^~~

<source>:38:18: warning: conversion from 'double' to 'int' may change value [-Wfloat-conversion]

38 |        *target = *source;

   |                  ^~~~~~~

In file included from /opt/compiler-explorer/gcc-trunk-20180917/include/c++/9.0.0/bits/char_traits.h:39,

                 from /opt/compiler-explorer/gcc-trunk-20180917/include/c++/9.0.0/ios:40,

                 from /opt/compiler-explorer/gcc-trunk-20180917/include/c++/9.0.0/ostream:38,

                 from /opt/compiler-explorer/gcc-trunk-20180917/include/c++/9.0.0/iostream:39,

                 from <source>:1:

/opt/compiler-explorer/gcc-trunk-20180917/include/c++/9.0.0/bits/stl_algobase.h: In instantiation of 'static _OI std::__copy_move<false, false, std::random_access_iterator_tag>::__copy_m(_II, _II, _OI) [with _II = double*; _OI = int*]':

/opt/compiler-explorer/gcc-trunk-20180917/include/c++/9.0.0/bits/stl_algobase.h:400:30:   required from '_OI std::__copy_move_a(_II, _II, _OI) [with bool _IsMove = false; _II = double*; _OI = int*]'

/opt/compiler-explorer/gcc-trunk-20180917/include/c++/9.0.0/bits/stl_algobase.h:437:30:   required from '_OI std::__copy_move_a2(_II, _II, _OI) [with bool _IsMove = false; _II = __gnu_cxx::__normal_iterator<double*, std::vector<double> >; _OI = __gnu_cxx::__normal_iterator<int*, std::vector<int> >]'

/opt/compiler-explorer/gcc-trunk-20180917/include/c++/9.0.0/bits/stl_algobase.h:470:7:   required from '_OI std::copy(_II, _II, _OI) [with _II = __gnu_cxx::__normal_iterator<double*, std::vector<double> >; _OI = __gnu_cxx::__normal_iterator<int*, std::vector<int> >]'

<source>:28:63:   required from here

/opt/compiler-explorer/gcc-trunk-20180917/include/c++/9.0.0/bits/stl_algobase.h:338:18: warning: conversion from 'double' to 'int' may change value [-Wfloat-conversion]

338 |        *__result = *__first;

    |                  ^

Compiler returned: 0

关于clang:这个标志集相当冗长,实际上并没有提供更多的洞见。

感谢您的尝试并指引我到godbolt页面,但是您回答中的警告是关于vector::push_back和直接赋值*target = *source;,而不是已经在问题中提到的std::copy - Pates
它不是说来自源代码第28行,即std::copy…抱歉,目前无法查找。 - user4290866
如果我注释掉copy这一行,我也会看到assign警告。所以你的答案至少给了我一个特定搜索这种错误的方法。虽然它并不是解决我的根本问题的令人满意的解决方案,但它回答了我的问题。 - Pates

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接