了解 -Weffc++

Understanding -Weffc++

提问人:chris 提问时间:7/16/2012 最后编辑:Robᵩchris 更新时间:11/23/2022 访问量:24295

问:

请考虑以下程序:

#include <string>

struct S {
    S (){}

private:
    void *ptr = nullptr;
    std::string str = "";
};

int main(){}

当在 GCC 4.7.1 上编译时,这将吐出:-Weffc++

warning: 'struct S' has pointer data members [-Weffc++]
warning:   but does not override 'S(const S&)' [-Weffc++]
warning:   or 'operator=(const S&)' [-Weffc++]

这通常没有问题,除了这个例子中的几件事:

  1. 如果我注释掉任何构造函数、指针声明或字符串声明,警告就会消失。这很奇怪,因为您认为仅指针就足够了,但事实并非如此。此外,将字符串声明更改为整数声明也会导致它消失,因此它只有在有字符串(或可能是其他选择类)时才会出现。为什么在这种情况下警告会消失?

  2. 通常,当指针所做的所有操作都指向现有变量(通常由操作系统维护)时,会出现此警告。没有 ,也没有 .在这些情况下,当带有句柄的类被复制时,我不想要深层复制。我希望两个句柄都指向同一个内部对象(例如窗口)。有没有办法让编译器意识到这一点,而不会不必要地重载复制构造函数和赋值运算符,或者完全禁用警告?为什么当三法则甚至不适用时,我首先会感到困扰?newdelete#pragma

C 指针 G++ 编译器警告 三法则

评论

1赞 S.S. Anne 8/4/2019
当我第一次看到这个警告时,我以为它的意思是“F*ck C++”,而不是“有效的C++”。他们需要为他们的警告选择更好的名称。

答:

5赞 Arpegius 7/16/2012 #1
  1. 当你这样做时,你就有一个 POD 结构。因为它不能有任何构造函数,所以不费心检查。-Weffc++

  2. 使用引用或对象或包装指针的任何其他对象。shared_ptr

评论

1赞 chris 7/16/2012
我有点认为#1 可能是这样。但是对于 #2,我从未真正看到或想象过将它们用于用于与系统交互的句柄。传递指针就是您所做的一切;你可以把它当作一个指针,因为重要的是它指向的地址,而不是里面的内容。从技术上讲,窗口句柄是 .使用方式是这样的:每个指针方面都已经处理好了;这有点像它已经是一个智能指针。在这种情况下,你会怎么做?void *HWND hwnd = CreateWindow (...); ShowWindow (hwnd, SW_SHOW);
0赞 Arpegius 7/16/2012
不知道是什么,但如果这是一个指针并且你有,你可能必须调用os一些东西。那么它是绑定到析构函数的 shared_ptr<HWND> 的好地方,它不是,不适合你。HWNDCreateWindowDestroyWindowDestroyWindow-Weffect
0赞 chris 7/16/2012
是的,这是存储为 .有趣的是,这通常是使窗口句柄超出范围的原因。其他人可能不需要您调用某些内容来删除它们。问题是它就像一个 ,这是不必要的。它应该更像是一个 ,但句柄不是你取消引用的东西或任何东西。在这种情况下,可以将指针视为正态变量。void *DestroyWindowshared_ptr<HWND>HWND *shared_ptr<void>
0赞 Arpegius 7/16/2012
是的,看起来 HWND 不是为 C++ 设计的。无论如何,将旧的 C 结构包装成一些类是好主意,以使 C++ 更有效。优点是该类在概念建模中发挥作用。
0赞 chris 7/16/2012
是的,大多数 winapi 都是 C。问题在于,当您将它们包装在类中时,但由于它们在技术上是指针,因此警告会不请自来地启动。
27赞 Jonathan Wakely 7/18/2012 #2

GCC有几个问题,我从不使用它。检查“问题”的代码非常简单,因此警告最终过于生硬和无用。-Weffc++

该特定警告基于有效C++第一版的第11项,Scott在以后的版本中对其进行了更改(为了更好)。G++ 代码不检查实际的动态分配,只检查指针成员是否存在。

在比较第一版和第三版的指南时,请参阅我在 GCC 的 bugzilla 中写的关于此警告的内容:

第 11 项:定义 copy 构造函数和 assignment 运算符的类 动态分配的内存。

替换为第 14 项:“仔细考虑复制行为 资源管理类“ - 建议不那么具体,但更有用。我是 不知道如何把它变成警告!

评论

3赞 Johan Lundberg 2/20/2013
-Weffc++ 的另一个问题:不允许在私有基类上使用非虚拟析构函数,这是没有充分理由的。
0赞 digitalTrilunaire 11/23/2022 #3

老问题,但“这通常没有问题”并不完全正确:

-Weffc++ 强制代码反映该行为。这里说的是,如果您按原样使用代码,则隐式复制运算符只会在与原始结构相同的地址上创建“ptr”点。

也许这就是你想要的原因,但它只是警告你,因为这是一种隐含的行为。对于正在编写代码的您来说,这可能很清楚,但对于其他开发人员来说,这很清楚吗?

要摆脱此警告,您应该做的是显式删除 copy 和 = 运算符或定义它们。要删除复制构造函数,您可以执行以下操作:

S(const S&) = delete;