new confusion spawned by -Weffc++

I once read that "the only valid result of true research is to create two questions where there was previously only one." This is brought home to me once again, now that I'm using -Weffc++ compile flag. As desired, it is flagging all missing variables when I use init lists. However, it also produced this odd warning on each of my classes:

vlistview.h:49: warning: `class CVListView' has pointer data members
vlistview.h:49: warning: but does not override `CVListView(const CVListView&)'
vlistview.h:49: warning: or `operator=(const CVListView&)'

The first thing I learned from this was that HANDLE, and its derivative HWND, are *not* simple numbers (as I always assumed) but are void *, thus the warning (the relevant classes all contain HWND values).

When I researched this obtuse warning, I received a lesson and a caution. The lesson was that I should overload both "const Classname&" constructor, and the copy constructor. The warning was that I have to be careful with operator=, when the data members are pointers, because when the destructor for the copied instance is called, the pointers will be destroyed, which will invalidate the pointer in the original instance of the class. Furthermore, I don't really *know* how to copy these objects that I'm pointing to, since they are void pointers (in fact, in the case of Windows objects, I cannot know how to copy them).

What someone at DaniWeb suggested to solve this problem, is to declare these two operations as empty functions with no body, and make them private member functions, so nobody can actually call them:

private:
CStatusBar operator=(const CStatusBar src) ;
CStatusBar(const CStatusBar&);
public:
etc...

So I did this, it works, and resolves the warnings. Everything is good, everyone is happy... except...

I don't really know what I just did by doing this... clearly I've disabled the copy constructor, which is probably fine since I cannot really copy these pointers anyway, due to the destructor problem. What I'd like to know from the experts here is, what other ramifications of these statements are there, that I don't know about? Are there any hidden traps in this that I should beware of?





The lesson was that I should overload both "const Classname&" constructor, and the copy constructor.

The "const classname&" constructor IS the copy constructor. </technicality>

I don't really know what I just did by doing this...

The compiler will automatically generate a "generic" copy constructor and assignment operator for your class. The generic versions simply do a copy of each individual members. This often is problematic for pointers because pointers probably need to be deep copied, otherwise two different classes will have ownership of the same object.

By providing your own copy constructor and assignment operator, you are telling the compiler not to automatically generate the generic version, and are saying it should use your version instead.

By making your version private, you are disallowing anyone to access them (ie nobody but your class can copy it). If outside code tries to copy/assign an object, it will get a compiler error.

By failing to give the functions a body, you are ensuring that even if your class accidentally tries to copy/assign an object, it will get a linker error.

What I'd like to know from the experts here is, what other ramifications of these statements are there, that I don't know about? Are there any hidden traps in this that I should beware of?


Not really. The biggest "trap" is that you'll get the compiler/linker errors if you accidentally try to copy an object. But that's not really a trap because it's what this code is designed to do.
Last edited on
Oh, okay, now I see one thing I missed before; I thought "operator=" was the COPY constructor, now (after a little more reading) I see it's the ASSIGNMENT constructor (or operator), which probably should have been apparent, but I missed it.

So what I'm disabling is both the copy constructor and assignment operator, which is in fact my intention; for all the classes that I've created so far, the user creates an instance with specific arguments relevant to the situation; copying some other instance really doesn't have much relevance.

Hopefully I've left enough comments in my code that I'll understand the compiler errors if I *do* try to copy them... 8-{)

Note that in C++11, this is now the preferred way to "delete" a function:

1
2
CStatusBar operator=(const CStatusBar src)=delete;
CStatusBar(const CStatusBar&)=delete;


This gives you a meaningful error at compile time instead of a semi-cryptic one in the linking stage.
If you wish to preserve compatibility with C++03, define a macro DELETED that translates to =delete in C++11 and nothing otherwise.
Topic archived. No new replies allowed.