【问题标题】:Visual Studio 2015: No signed/unsigned mismatch warning in std::make_unique?Visual Studio 2015:std::make_unique 中没有带符号/无符号不匹配警告?
【发布时间】:2018-02-21 19:40:29
【问题描述】:

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

#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)

【问题讨论】:

    标签: c++ visual-studio-2015 warnings unique-ptr signedness


    【解决方案1】:

    您会看到几种效果的组合。

    1. main() 中的调用是完全合法的,因为make_unique 模板实例化与您提供给它的签名数据类型相匹配。
    2. make_unique 的实现不会产生警告,因为 警告通常在系统标头中被禁用。
    3. Visual Studio 似乎无法检测到潜力(但不是 确定make_unique内部的符号转换问题。

    更详细的:

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

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

    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&lt;MyClass&gt;(-1) 时,模板是 为一个 signed 整数实例化。因此,您不会在您的 代码,因为没有发生无符号/有符号转换。

    2。系统标头通常会禁用警告。

    但是,您可以正确地期待来自make_unique 的警告 执行。毕竟,当new T(...) 被您签名时 参数,有符号/无符号转换仍然发生。作为一个例子,采取 以下程序:

    #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: 在 'std::unique_ptr<_tp> custom_make_unique(Args&& ...) [with T = MyClass; Args = {int}]':
    test.cpp:17:48: 从这里需要
    test.cpp:12:63:警告:从“int”转换为“unsigned int”可能会更改结果的符号 [-Wsign-conversion]
    return std::unique_ptr(new T(std::forward(args)...));

    所以问题是,为什么您没有收到std::make_unique() 的警告 执行?答案本质上是编译器将这些静音 其系统标头的警告。例如,&lt;memory&gt; 的 GCC 版本 标头包含编译指示

    #pragma GCC system_header
    

    只要这个编译指示出现在头文件中,编译器就不再 报告该标题内所有内容的警告。从 GCC documentation:

    声明操作系统和运行时接口的头文件 库通常不能用严格符合的 C 语言编写。因此,GCC 对系统头文件中的代码进行特殊处理。所有警告,除了 那些由‘#warning’(见诊断)生成的,在 GCC 运行时被抑制 处理系统头文件。

    另请参阅 this SO post 为 更多细节。据推测,Visual Studio 采用了类似的方法 编译器(正如您在评论中所写,标题暂时减少了 警告级别)。

    3。您似乎遇到了 VisualStudio 限制。

    在 VisualStudio 的情况下,还有其他一些东西在起作用。注意如何 上面的 GCC 警告说可能存在符号转换问题(取决于 关于用户将稍后输入custom_make_unique的价值观)。它出现 VisualStudio 只能在存在 确定 符号转换问题时发出警告。 请参阅以下程序:

    #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)
    }
    

    Try it online.

    【讨论】:

    • 哇,答案很全面,非常感谢。我用你的custom_make_unique() 进行了尝试,但它仍然没有发出警告(即使也将custom_forwardcustom_remove_reference 复制并粘贴到我自己的代码中)。至少我现在知道要寻找什么了。
    • 嗯。一般来说,VisualStudio 可能只在它可以推断出存在符号转换问题的情况下才设法发出警告。在我上面的 GCC 示例中,编译器只能推断出可能存在问题(取决于您稍后输入custom_make_unique 的值)。所以也许你也遇到了 Visual Studio 的限制。
    • 确实,memory 标头使用#pragma warning(push,3) 将警告级别暂时降低到 3,这可以解释缺少的警告。尽管如此,它并没有解释为什么custom_make_unique() 也不起作用。
    • 感谢您的检查。我更新了我的答案(幸运的是 rextester.com 提供了一个 VC++ 编译器)。
    猜你喜欢
    • 1970-01-01
    • 2014-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    相关资源
    最近更新 更多