关于c ++:Visual Studio 2015:std :: make_unique中没有签名/未签名的不匹配警告?

Visual Studio 2015: No signed/unsigned mismatch warning in std::make_unique?

我只是在代码中发现了一个错误,我很困惑它的发生,因为它是一个简单的有符号/无符号不匹配-根本不应该发生,因为我将警告级别4编译为错误。 所以我试图重现它,这很简单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <memory>

class MyClass {
public:
    MyClass( unsigned ) {}
};
int main()
{
    MyClass* rawP = new MyClass(-1);                // issues a warning, as expected
    auto uniqueP = std::make_unique<MyClass>(-1);   // NO WARNING??!

    // silence the compiler
    rawP;
    uniqueP;

    return 0;
}

现在我问自己:这是什么原因? 这是VS中的错误,还是std :: make_unique的普遍缺点? 有什么办法可以解决? (Visual Studio 2015社区更新3)


您正在看到几种效果的组合。

  • main()中的调用是完全合法的,因为make_unique
    模板实例化与您提供的签名数据类型匹配。
  • make_unique的实现不会生成警告,因为
    警告通常在系统标题内被禁用。
  • Visual Studio似乎无法检测到潜力(但不能
    (绝对)在make_unique内的符号转换问题。
  • 更详细地:

    1.模板实例化实际上是合法的。

    std::make_unique的典型实现如下所示(比较
    cppreference):

    1
    2
    3
    4
    5
    template <typename T, typename... Args>
    inline std::unique_ptr< T > make_unique(Args&&... args)
    {
      return std::unique_ptr< T >(new T(std::forward<Args>(args)...));
    }

    在您的情况下,调用std::make_unique(-1)时,模板为
    为一个有符号整数实例化。因此,您不会收到警告
    代码,因为没有未签名/已签名的转换发生。

    2.系统标题通常禁用警告。

    但是,您可以正确地预期make_unique发出警告
    实施。毕竟,当new T(...)与您的签名一起被调用时
    参数,仍然会发生有符号/无符号转换。作为一个例子,
    以下程序:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    #include <memory>

    class MyClass
    {
    public:
      MyClass(unsigned) { }
    };

    template <typename T, typename... Args>
    inline std::unique_ptr< T > custom_make_unique(Args&&... args)
    {
      return std::unique_ptr< T >(new T(std::forward<Args>(args)...));
    }

    int main()
    {
      auto uniqueP = custom_make_unique<MyClass>(-1);
      (void) uniqueP;
      return 0;
    }

    当我使用带有-Wsign-conversion的GCC进行编译时,收到警告

    test.cpp: In instantiation of 'std::unique_ptr<_Tp> custom_make_unique(Args&& ...) [with T = MyClass; Args = {int}]':
    test.cpp:17:48: required from here
    test.cpp:12:63: warning: conversion to 'unsigned int' from 'int' may change the sign of the result [-Wsign-conversion]
    return std::unique_ptr(new T(std::forward(args)...));

    所以问题是,为什么您没有收到std::make_unique()的警告?
    实施?答案本质上是编译器使这些沉默
    系统标题警告。例如,的GCC版本
    标头包含杂注

    1
    #pragma GCC system_header

    头文件中存在此编译指示后,编译器将不再
    报告该标头中所有内容的警告。从
    GCC文档:

    The header files declaring interfaces to the operating system and runtime
    libraries often cannot be written in strictly conforming C. Therefore, GCC
    gives code found in system headers special treatment. All warnings, other than
    those generated by ‘#warning’ (see Diagnostics), are suppressed while GCC is
    processing a system header.

    也可以看看
    这个SO职位
    更多细节。大概Visual Studio采取了类似的方法
    编译器(正如您在评论中所写的那样,标头会暂时减少
    警告级别)。

    3.看起来您遇到了VisualStudio限制。

    对于VisualStudio,还有其他工作。请注意
    上面的GCC警告表示可能存在符号转换问题(具体取决于
    用户稍后将输入custom_make_unique的值)。它出现
    只有存在明确的符号转换问题时,VisualStudio才能发出警告。
    请参阅以下程序:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #include <iostream>

    void f(unsigned) { }

    template <typename T>
    void g(T val) { f(val); } // GCC issues a warning, VS does NOT

    int main()
    {
      f(-1); // GCC and VS issue a warning
      g(-1); // no conversion warning here (g<int> instantiated)
    }

    在线尝试。