C++ 在使用复制构造函数和赋值时生成警告
有没有办法让编译器(这里特别是MSVC 2017,但其他可能也很有趣)在使用特定类的复制构造函数和复制赋值运算符的位置发出警告(并且可以在每个调用站点显式禁止,即使是间接的) 询问如何生成编译错误,现在使用C++11删除的方法很容易,但我希望代码仍然可以编译,只输出警告 原因是我有一个类,它目前在整个代码库中被大量复制。我不想阻止它被复制(其中一些是必要的),但我确实想查看每个位置,以确定是否应该将其更改为移动或通过引用传递 让编译器临时标记构造函数的使用作为警告似乎是一种很好的方法 我尝试添加如下内容: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删除的方法很容易,但我希望代码仍然可以编译,只输出警告 原因是我有一个类,它目前在整个代码库中被大量复制。我不想阻止它被复制(其中一些是必要的),但我确实想查看每个位置,以确定是否应该将其更改为移动或通过引用传递 让编译器临时标记构造函数的使用作为警告似乎是一种很好的方法 我尝试添加
__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只会找到执行复制的那些)如果这些工具能够像命名方法使用一样轻松地找到构造函数/运算符的用法,那就太好了。不幸的是,这些不可抑制的代码位之一位于包含大量源文件的头文件中,因此,这一行会产生大量噪音。您可以使用
受保护:
或专用:
。这会使它产生错误。一旦出现错误,您可以更改调用站点以使用执行操作的方法(如工厂函数)。仅将它们设置为错误有什么错,修复您要更改的位置周围的代码,然后恢复正常操作?听起来它会做和你现在尝试做的一样的事情——修改代码,发现问题,修复它们。