Understanding -Weffc++
Asked Answered
L

3

19

Consider the following program:

#include <string>

struct S {
    S (){}

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

int main(){}

This, when compiled with -Weffc++ on GCC 4.7.1, will spit out:

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

That's no problem normally, except for a couple things with this example:

  1. If I comment out any of the constructor, the pointer declaration, or the string declaration, the warning disappears. This is odd because you'd think the pointer alone would be enough, but it isn't. Furthermore, changing the string declaration to an integer declaration causes it to disappear as well, so it only comes up when there's a string (or probably other choice classes) with it. Why does the warning disappear under these circumstances?

  2. Often times this warning comes up when all the pointer is doing is pointing to an existing variable (most often maintained by the OS). There's no new, and no delete. When the class with the handle, in these cases, is copied, I don't want a deep copy. I want both handles to point to the same internal object (like a window, for example). Is there any way to make the compiler realize this without unnecessarily overloading the copy constructor and assignment operator, or disabling the warning completely with #pragma? Why am I being bothered in the first place when the Rule of Three doesn't even apply?

Lunik answered 16/7, 2012 at 0:50 Comment(1)
When I first saw this warning, I thought it meant "F*ck C++", not "Effective C++". They need to choose better names for their warnings.Tham
O
28

GCC's -Weffc++ has several issues, I never use it. The code that checks for "problems" is pretty simplistic and so the warnings end up being far too blunt and unhelpful.

That particular warning is based on Item 11 of the first edition of Effective C++ and Scott changed it (for the better) in later editions. The G++ code doesn't check for actual dynamic allocation, just the presence of pointer members.

See what I wrote about this warning in GCC's bugzilla when comparing the guidelines in the first edition with the third edition:

Item 11: Define a copy constructor and an assignment operator for classes with dynamically allocated memory.

Replaced by Item 14: "Think carefully about copying behavior in resource-managing classes" - the advice is less specific, but more useful. I'm not sure how to turn it into a warning though!

Overcheck answered 17/7, 2012 at 19:17 Comment(1)
Another problem with -Weffc++: Having a non-virtual destructor on a private base class is not allowed, for no good reason.Compotation
R
5
  1. When you do it, you have a POD structure. As it cannot have any constructors, -Weffc++ doesn't bother checking.

  2. Use a reference or shared_ptr object or any other object that wrap a pointer.

Repair answered 16/7, 2012 at 2:47 Comment(8)
I kind of thought it might be something like that for #1. But for #2, I've never really seen or imagined the use of them for handles used to interact with the system. Passing the pointer around is all you do; you can treat it as if it's not a pointer at all, as all that's important is the address it points to, not what's in there. A window handle is technically a void *. The use goes something like HWND hwnd = CreateWindow (...); ShowWindow (hwnd, SW_SHOW); Every pointer aspect is taken care of already; it's sort of like it's already a smart pointer. What do you do in that case?Lunik
Don't know whats HWND but if that's a pointer and you have CreateWindow, you probably have to call DestroyWindow os something. Then it's good place for shared_ptr<HWND> with DestroyWindow binded to destructor, it not, -Weffect is not for you.Repair
Yes, that's one of the many objects stored as a void *. The funny thing about this one is that DestroyWindow is usually what makes the window handle go out of scope. Others might not require you to call something to delete them. The thing about shared_ptr<HWND> is that it's like a HWND *, which is unnecessary. It should be more like a shared_ptr<void>, but the handles aren't something you dereference or anything. In this case, the pointers can be thought of as normal variables.Lunik
Yeah it looks like HWND is not design for C++. Anyway is alwas good idea to wrap old C structures into some classes, to make C++ more effective. The protip is that the class plays role in conceptual modeling.Repair
Yeah, most of the winapi is C. The problem is when you wrap them in classes, but since they are technically pointers, the warning kicks in uninvited.Lunik
So you realy should consider overloading copy constructor and operator= in your wrapper, even if you just need to make them private, without any implementation, and then keep pointers to wrapers by shared_ptr. Anyway is not that I don't know aobut winapi, is more like I don't want to know, so technicly I was trolling.Repair
Well, that's depressing. Guess it just boils down to those options.Lunik
Well, bad designed code can be even more depresing. That's what i'm thinking about WinApi. Anyway if you don't want to code too much then templates are your friends.Repair
M
0

Old question but "That's no problem normally" is not totally true:

-Weffc++ force your code to reflect the behavior. What is saying here is if you are using the code as it is, the implicit copy operator will just make "ptr" point on the same address as the original struct.

MAYBE THAT WHY YOU WANT, but it just warns you because it is an implicit behavior. This can be clear for you that are writing the code, but will it be clear for an other dev?

What you should do to get rid of this warning is either explicitly delete the copy and = operator or define them. To delete a copy constructor you can do as follow:

S(const S&) = delete;
Matheson answered 23/11, 2022 at 14:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.