C++ 在使用复制构造函数和赋值时生成警告

C++ 在使用复制构造函数和赋值时生成警告,c++,visual-c++,visual-studio-2017,copy-constructor,suppress-warnings,C++,Visual C++,Visual Studio 2017,Copy Constructor,Suppress Warnings,有没有办法让编译器(这里特别是MSVC 2017,但其他可能也很有趣)在使用特定类的复制构造函数和复制赋值运算符的位置发出警告(并且可以在每个调用站点显式禁止,即使是间接的) 询问如何生成编译错误,现在使用C++11删除的方法很容易,但我希望代码仍然可以编译,只输出警告 原因是我有一个类,它目前在整个代码库中被大量复制。我不想阻止它被复制(其中一些是必要的),但我确实想查看每个位置,以确定是否应该将其更改为移动或通过引用传递 让编译器临时标记构造函数的使用作为警告似乎是一种很好的方法 我尝试添加

有没有办法让编译器(这里特别是MSVC 2017,但其他可能也很有趣)在使用特定类的复制构造函数和复制赋值运算符的位置发出警告(并且可以在每个调用站点显式禁止,即使是间接的)

询问如何生成编译错误,现在使用C++11删除的方法很容易,但我希望代码仍然可以编译,只输出警告

原因是我有一个类,它目前在整个代码库中被大量复制。我不想阻止它被复制(其中一些是必要的),但我确实想查看每个位置,以确定是否应该将其更改为移动或通过引用传递

让编译器临时标记构造函数的使用作为警告似乎是一种很好的方法

我尝试添加如下内容:

__declspec(deprecated) MyType(MyType const&) = default;
但这不起作用;显然,
=default
胜过任何其他修饰符

我做了同样的事情,但完全实现了该方法,这几乎奏效了——它在每个调用站点生成C4996,我可以查看这些,或者更改它们,或者添加一个:

#pragma warning(suppress:4996)
如果我很高兴这是必需的副本。(我最终计划删除这些,以及对构造函数的不赞成——这只是为了跟踪哪些我还没有处理过。)

不幸的是,有些情况我无法通过这种方式抑制,例如:

std::vector<MyType> list;
list.push_back(type);
list.emplace_back(MyType{ type });
std::向量列表;
列表。推回(类型);
list.emplace_back(MyType{type});
这些行中的每一行都会引发警告(第一行是因为它是具有常规复制构造函数的类中的字段声明),但只有第三行可以在此处直接禁止。前两个在
中引发警告,并且似乎不受此代码行中的警告抑制(或禁用)的影响


有什么方法可以解决这个问题,或者有什么其他方法可以满足我的要求吗?

这看起来并不完美,但我能够使用以下策略抑制噪音最大的情况(头文件中类的向量成员)。其余的案例在那之后表现得相当出色,不需要单独压制;它们可以被修复或忽略

  • 添加不推荐使用的副本和非不推荐使用的移动构造函数和分配:

    __declspec(deprecated) MyType(MyType const& o) { /* actual impl */ }
    __declspec(deprecated) MyType& operator=(MyType const& o) { /* impl */ return *this; }
    MyType(MyType&&) = default;
    MyType& operator=(MyType&&) = default;
    
  • 同时添加占位符非不推荐的转发类型:

    struct SuppressMyType : MyType
    {
        using MyType::MyType;
    #pragma warning(disable:4996)
        SuppressMyType(SuppressMyType const& o) : MyType(o) {}
        SuppressMyType& operator=(SuppressMyType const& o)
            { MyType::operator=(static_cast<MyType const&>(o)); return *this; }
        SuppressMyType(MyType const& o) : MyType(o) {}
        operator MyType() const { return *this; }
    #pragma warning(default:4996)
    };
    
    struct SuppressMyType:MyType
    {
    使用MyType::MyType;
    #杂注警告(禁用:4996)
    SuppressMyType(SuppressMyType常量&o):MyType(o){}
    SuppressMyType和运算符=(SuppressMyType常量和o)
    {MyType::operator=(static_cast(o));返回*this;}
    SuppressMyType(MyType常量和o):MyType(o){}
    运算符MyType()常量{return*this;}
    #pragma警告(默认值:4996)
    };
    
  • 更改副本打算使用
    SuppressMyType
    而不是
    MyType
    的位置

  • 修复其他位置,直到警告消失

  • 将所有
    SuppressMyType
    替换回
    MyType
    ,然后删除#1中添加的代码


  • 有点复杂,但它确实起到了作用。

    用另一种方法做后再考虑一下,用另一种方法做可能会更好(也更容易):

  • 将所有
    MyType
    替换为
    WarnMyType
    (当然
    MyType
    的实际定义除外)
  • 使用不推荐的构造函数添加
    WarnMyType

    struct WarnMyType : MyType
    {
        using MyType::MyType;
        __declspec(deprecated) WarnMyType(WarnMyType const& o) : MyType(o) {}
        __declspec(deprecated) WarnMyType& operator=(WarnMyType const& o)
            { MyType::operator=(static_cast<MyType const&>(o)); return *this; }
        WarnMyType(WarnMyType&&) = default;
        WarnMyType& operator=(WarnMyType&&) = default;
    };
    
    结构WarnMyType:MyType { 使用MyType::MyType; __declspec(已弃用)WarnMyType(WarnMyType const&o):MyType(o){} __declspec(已弃用)WarnMyType&operator=(WarnMyType const&o) {MyType::operator=(static_cast(o));返回*this;} WarnMyType(WarnMyType&&)=默认值; WarnMyType&运算符=(WarnMyType&&)=默认值; };
  • 检查时,逐渐将
    WarnMyType
    的用法改回
    MyType

  • 删除
    WarnMyType
  • 批量将
    WarnMyType
    的任何剩余使用替换回
    MyType
    (因为#3只会找到执行复制的那些)

  • 如果这些工具能够像命名方法使用一样轻松地找到构造函数/运算符的用法,那就太好了。

    不幸的是,这些不可抑制的代码位之一位于包含大量源文件的头文件中,因此,这一行会产生大量噪音。您可以使用
    受保护:
    专用:
    。这会使它产生错误。一旦出现错误,您可以更改调用站点以使用执行操作的方法(如工厂函数)。仅将它们设置为错误有什么错,修复您要更改的位置周围的代码,然后恢复正常操作?听起来它会做和你现在尝试做的一样的事情——修改代码,发现问题,修复它们。