是否有一种方法可以使编译器(在这里特别是MSVC 2017,但其他可能也很有趣)可以在使用特定类的复制构造函数和复制分配运算符的位置发出警告。 / em>(并且可以在每个调用站点上被显式抑制,即使是间接的)?
This question询问产生编译错误的问题,现在使用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 });
每行都会引发警告(第一行是因为它是具有常规复制构造函数的类中的字段声明),但此处仅第三行可以直接禁止显示。前两个在<vector>
内发出警告,并且似乎不受此代码行的警告抑制(或禁用)的影响。
是否有某种方法可以解决此问题,或者有其他方法可以完成我想要的事情?
答案 0 :(得分:1)
这似乎并不完美,但是我可以使用以下策略来抑制最嘈杂的情况(头文件中类的向量成员)。在那之后,其余案件表现得相当不错,不需要单独加以制止。它们可以被修复或忽略。
添加不建议使用的副本和不建议使用的move构造函数和赋值:
__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)
};
更改副本打算使用SuppressMyType
而非MyType
的位置。
修复其他地方,直到警告消失。
将所有SuppressMyType
替换回MyType
,然后删除#1中添加的代码。
有点令人费解,但是成功了。
答案 1 :(得分: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
。
WarnMyType
。WarnMyType
的所有剩余用途重新替换为MyType
(因为#3只会找到执行复制的地方)。如果这些工具使查找构造函数/运算符的用法像命名方法的用法一样容易...